2019-04-06 12:29:29 +00:00
# include <AK/Types.h>
2018-11-01 12:15:46 +00:00
# include "Process.h"
2018-10-16 09:01:38 +00:00
# include "kmalloc.h"
# include "StdLib.h"
# include "i386.h"
2019-04-06 18:29:48 +00:00
# include <Kernel/FileSystem/FileDescriptor.h>
2019-04-03 10:25:24 +00:00
# include <Kernel/FileSystem/VirtualFileSystem.h>
2019-04-03 10:36:40 +00:00
# include <Kernel/Devices/NullDevice.h>
2019-04-03 10:30:04 +00:00
# include <Kernel/ELF/ELFLoader.h>
2019-04-03 13:13:07 +00:00
# include <Kernel/VM/MemoryManager.h>
2018-10-25 11:53:49 +00:00
# include "i8253.h"
2018-10-25 15:29:49 +00:00
# include "RTC.h"
2018-12-03 23:27:16 +00:00
# include <AK/StdLibExtras.h>
2018-11-06 14:45:16 +00:00
# include <LibC/signal_numbers.h>
2019-01-22 00:12:53 +00:00
# include <LibC/errno_numbers.h>
2018-11-07 20:19:47 +00:00
# include "Syscall.h"
2018-11-07 21:15:02 +00:00
# include "Scheduler.h"
2019-04-06 18:29:48 +00:00
# include <Kernel/FileSystem/FIFO.h>
2018-12-24 21:59:10 +00:00
# include "KSyms.h"
2019-04-06 18:29:48 +00:00
# include <Kernel/Net/Socket.h>
2019-04-03 10:28:45 +00:00
# include <Kernel/TTY/MasterPTY.h>
2019-04-03 10:30:04 +00:00
# include <Kernel/ELF/exec_elf.h>
2019-02-16 23:13:47 +00:00
# include <AK/StringBuilder.h>
2019-05-18 00:00:01 +00:00
# include <AK/Time.h>
2019-04-09 00:37:05 +00:00
# include <Kernel/SharedMemory.h>
2019-04-22 16:44:45 +00:00
# include <Kernel/ProcessTracer.h>
2018-10-16 09:01:38 +00:00
2019-05-19 08:24:28 +00:00
//#define DEBUG_POLL_SELECT
2018-10-23 08:12:50 +00:00
//#define DEBUG_IO
2019-03-27 14:07:12 +00:00
//#define TASK_DEBUG
//#define FORK_DEBUG
2019-03-23 21:03:17 +00:00
# define SIGNAL_DEBUG
2019-02-16 23:13:47 +00:00
//#define SHARED_BUFFER_DEBUG
2018-11-05 12:48:07 +00:00
2018-10-16 09:01:38 +00:00
static pid_t next_pid ;
2018-11-07 21:15:02 +00:00
InlineLinkedList < Process > * g_processes ;
2018-10-26 07:54:29 +00:00
static String * s_hostname ;
2019-02-07 09:29:26 +00:00
static Lock * s_hostname_lock ;
2018-10-26 12:56:21 +00:00
2018-11-01 12:15:46 +00:00
void Process : : initialize ( )
2018-10-16 09:01:38 +00:00
{
next_pid = 0 ;
2018-11-07 21:15:02 +00:00
g_processes = new InlineLinkedList < Process > ;
2018-11-16 23:23:39 +00:00
s_hostname = new String ( " courage " ) ;
2019-02-07 09:29:26 +00:00
s_hostname_lock = new Lock ;
2018-11-02 13:06:48 +00:00
}
2019-02-03 11:33:11 +00:00
Vector < pid_t > Process : : all_pids ( )
{
Vector < pid_t > pids ;
2019-02-06 17:45:21 +00:00
InterruptDisabler disabler ;
2019-04-15 22:37:35 +00:00
pids . ensure_capacity ( g_processes - > size_slow ( ) ) ;
2019-02-03 11:33:11 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) )
2019-02-06 17:45:21 +00:00
pids . append ( process - > pid ( ) ) ;
2019-02-03 11:33:11 +00:00
return pids ;
}
2019-01-31 16:31:23 +00:00
Vector < Process * > Process : : all_processes ( )
2018-10-23 10:44:46 +00:00
{
2018-11-01 12:15:46 +00:00
Vector < Process * > processes ;
2019-02-06 17:45:21 +00:00
InterruptDisabler disabler ;
2019-04-15 22:37:35 +00:00
processes . ensure_capacity ( g_processes - > size_slow ( ) ) ;
2018-11-07 21:15:02 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) )
2019-02-06 17:45:21 +00:00
processes . append ( process ) ;
2018-11-01 12:15:46 +00:00
return processes ;
2018-10-23 10:44:46 +00:00
}
2019-02-27 11:32:53 +00:00
bool Process : : in_group ( gid_t gid ) const
{
return m_gids . contains ( gid ) ;
}
2019-05-17 02:39:22 +00:00
Range Process : : allocate_range ( LinearAddress laddr , size_t size )
2018-10-18 11:05:00 +00:00
{
2019-05-17 01:40:15 +00:00
laddr . mask ( PAGE_MASK ) ;
2019-01-12 23:27:25 +00:00
size = PAGE_ROUND_UP ( size ) ;
2019-05-17 01:40:15 +00:00
if ( laddr . is_null ( ) )
2019-05-20 02:46:29 +00:00
return page_directory ( ) . range_allocator ( ) . allocate_anywhere ( size ) ;
return page_directory ( ) . range_allocator ( ) . allocate_specific ( laddr , size ) ;
2019-05-17 02:39:22 +00:00
}
2019-05-17 01:40:15 +00:00
2019-05-17 02:39:22 +00:00
Region * Process : : allocate_region ( LinearAddress laddr , size_t size , String & & name , bool is_readable , bool is_writable , bool commit )
{
auto range = allocate_range ( laddr , size ) ;
if ( ! range . is_valid ( ) )
return nullptr ;
2019-05-17 02:32:08 +00:00
m_regions . append ( adopt ( * new Region ( range , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2019-01-22 04:01:00 +00:00
if ( commit )
m_regions . last ( ) - > commit ( ) ;
2018-10-18 12:53:00 +00:00
return m_regions . last ( ) . ptr ( ) ;
2018-10-18 11:05:00 +00:00
}
2019-01-16 11:57:07 +00:00
Region * Process : : allocate_file_backed_region ( LinearAddress laddr , size_t size , RetainPtr < Inode > & & inode , String & & name , bool is_readable , bool is_writable )
2018-11-08 11:59:16 +00:00
{
2019-05-17 02:39:22 +00:00
auto range = allocate_range ( laddr , size ) ;
if ( ! range . is_valid ( ) )
return nullptr ;
2019-05-17 02:32:08 +00:00
m_regions . append ( adopt ( * new Region ( range , move ( inode ) , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2018-11-08 11:59:16 +00:00
return m_regions . last ( ) . ptr ( ) ;
}
2019-02-25 15:04:08 +00:00
Region * Process : : allocate_region_with_vmo ( LinearAddress laddr , size_t size , Retained < VMObject > & & vmo , size_t offset_in_vmo , String & & name , bool is_readable , bool is_writable )
2018-11-08 20:20:09 +00:00
{
2019-05-17 02:39:22 +00:00
auto range = allocate_range ( laddr , size ) ;
if ( ! range . is_valid ( ) )
return nullptr ;
2018-11-08 20:20:09 +00:00
offset_in_vmo & = PAGE_MASK ;
2019-05-17 02:32:08 +00:00
m_regions . append ( adopt ( * new Region ( range , move ( vmo ) , offset_in_vmo , move ( name ) , is_readable , is_writable ) ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * this , * m_regions . last ( ) ) ;
2018-11-08 20:20:09 +00:00
return m_regions . last ( ) . ptr ( ) ;
}
2018-11-03 10:28:23 +00:00
bool Process : : deallocate_region ( Region & region )
2018-10-24 07:48:24 +00:00
{
2018-10-28 08:36:21 +00:00
InterruptDisabler disabler ;
2019-02-25 21:06:55 +00:00
for ( int i = 0 ; i < m_regions . size ( ) ; + + i ) {
2019-04-14 00:36:06 +00:00
if ( m_regions [ i ] = = & region ) {
2019-05-20 02:46:29 +00:00
page_directory ( ) . range_allocator ( ) . deallocate ( { region . laddr ( ) , region . size ( ) } ) ;
2019-01-22 04:01:00 +00:00
MM . unmap_region ( region ) ;
2018-10-24 07:48:24 +00:00
m_regions . remove ( i ) ;
return true ;
}
}
return false ;
}
2019-01-31 16:31:23 +00:00
Region * Process : : region_from_range ( LinearAddress laddr , size_t size )
2018-10-24 07:48:24 +00:00
{
2019-02-17 07:32:08 +00:00
size = PAGE_ROUND_UP ( size ) ;
2018-10-24 07:48:24 +00:00
for ( auto & region : m_regions ) {
2019-01-24 17:09:46 +00:00
if ( region - > laddr ( ) = = laddr & & region - > size ( ) = = size )
2018-10-24 07:48:24 +00:00
return region . ptr ( ) ;
}
return nullptr ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ set_mmap_name ( void * addr , size_t size , const char * name )
2018-10-28 08:57:22 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( name ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-01-31 16:31:23 +00:00
auto * region = region_from_range ( LinearAddress ( ( dword ) addr ) , size ) ;
2018-10-28 08:57:22 +00:00
if ( ! region )
return - EINVAL ;
2019-01-24 17:09:46 +00:00
region - > set_name ( String ( name ) ) ;
2018-10-28 08:57:22 +00:00
return 0 ;
}
2018-11-08 10:37:01 +00:00
void * Process : : sys $ mmap ( const Syscall : : SC_mmap_params * params )
2018-10-24 07:48:24 +00:00
{
2018-11-16 15:10:59 +00:00
if ( ! validate_read ( params , sizeof ( Syscall : : SC_mmap_params ) ) )
return ( void * ) - EFAULT ;
2019-05-19 13:54:56 +00:00
if ( params - > name & & ! validate_read_str ( params - > name ) )
return ( void * ) - EFAULT ;
2018-11-08 10:37:01 +00:00
void * addr = ( void * ) params - > addr ;
size_t size = params - > size ;
int prot = params - > prot ;
int flags = params - > flags ;
int fd = params - > fd ;
2019-01-23 05:53:01 +00:00
off_t offset = params - > offset ;
2019-05-19 13:54:56 +00:00
const char * name = params - > name ;
2018-11-08 11:59:16 +00:00
if ( size = = 0 )
return ( void * ) - EINVAL ;
2019-02-09 07:44:46 +00:00
if ( ( dword ) addr & ~ PAGE_MASK )
2018-11-08 11:59:16 +00:00
return ( void * ) - EINVAL ;
if ( flags & MAP_ANONYMOUS ) {
2019-02-16 23:13:47 +00:00
auto * region = allocate_region ( LinearAddress ( ( dword ) addr ) , size , " mmap " , prot & PROT_READ , prot & PROT_WRITE , false ) ;
2018-11-08 11:59:16 +00:00
if ( ! region )
return ( void * ) - ENOMEM ;
2019-02-16 23:13:47 +00:00
if ( flags & MAP_SHARED )
region - > set_shared ( true ) ;
2019-05-19 13:54:56 +00:00
if ( name )
region - > set_name ( name ) ;
2019-01-24 17:09:46 +00:00
return region - > laddr ( ) . as_ptr ( ) ;
2018-11-08 11:59:16 +00:00
}
if ( offset & ~ PAGE_MASK )
return ( void * ) - EINVAL ;
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return ( void * ) - EBADF ;
2019-04-28 13:02:55 +00:00
auto region_or_error = descriptor - > mmap ( * this , LinearAddress ( ( dword ) addr ) , offset , size , prot ) ;
if ( region_or_error . is_error ( ) )
return ( void * ) ( int ) region_or_error . error ( ) ;
auto region = region_or_error . value ( ) ;
2019-02-16 23:13:47 +00:00
if ( flags & MAP_SHARED )
region - > set_shared ( true ) ;
2019-05-19 13:54:56 +00:00
if ( name )
region - > set_name ( name ) ;
2019-01-24 17:09:46 +00:00
return region - > laddr ( ) . as_ptr ( ) ;
2018-10-24 07:48:24 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ munmap ( void * addr , size_t size )
2018-10-24 07:48:24 +00:00
{
2019-01-31 16:31:23 +00:00
auto * region = region_from_range ( LinearAddress ( ( dword ) addr ) , size ) ;
2018-10-24 07:48:24 +00:00
if ( ! region )
2019-02-16 23:13:47 +00:00
return - EINVAL ;
2018-11-03 10:28:23 +00:00
if ( ! deallocate_region ( * region ) )
2019-02-16 23:13:47 +00:00
return - EINVAL ;
2018-10-24 07:48:24 +00:00
return 0 ;
}
2019-02-25 20:19:57 +00:00
int Process : : sys $ gethostname ( char * buffer , ssize_t size )
2018-10-26 07:54:29 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2019-02-07 09:29:26 +00:00
LOCKER ( * s_hostname_lock ) ;
if ( size < ( s_hostname - > length ( ) + 1 ) )
2018-10-26 07:54:29 +00:00
return - ENAMETOOLONG ;
2019-02-07 09:29:26 +00:00
strcpy ( buffer , s_hostname - > characters ( ) ) ;
2018-10-26 09:16:56 +00:00
return 0 ;
2018-10-26 07:54:29 +00:00
}
2018-11-02 19:41:58 +00:00
Process * Process : : fork ( RegisterDump & regs )
{
2019-01-31 16:31:23 +00:00
auto * child = new Process ( String ( m_name ) , m_uid , m_gid , m_pid , m_ring , m_cwd . copy_ref ( ) , m_executable . copy_ref ( ) , m_tty , this ) ;
2018-11-10 22:29:07 +00:00
if ( ! child )
return nullptr ;
2018-11-02 19:41:58 +00:00
# ifdef FORK_DEBUG
dbgprintf ( " fork: child=%p \n " , child ) ;
# endif
for ( auto & region : m_regions ) {
# ifdef FORK_DEBUG
2019-02-26 14:57:59 +00:00
dbgprintf ( " fork: cloning Region{%p} \" %s \" L%x \n " , region . ptr ( ) , region - > name ( ) . characters ( ) , region - > laddr ( ) . get ( ) ) ;
2018-11-02 19:41:58 +00:00
# endif
auto cloned_region = region - > clone ( ) ;
child - > m_regions . append ( move ( cloned_region ) ) ;
2018-12-03 00:38:22 +00:00
MM . map_region ( * child , * child - > m_regions . last ( ) ) ;
2018-11-02 19:41:58 +00:00
}
2019-01-21 00:49:30 +00:00
for ( auto gid : m_gids )
child - > m_gids . set ( gid ) ;
2019-03-23 21:03:17 +00:00
auto & child_tss = child - > main_thread ( ) . m_tss ;
child_tss . eax = 0 ; // fork() returns 0 in the child :^)
child_tss . ebx = regs . ebx ;
child_tss . ecx = regs . ecx ;
child_tss . edx = regs . edx ;
child_tss . ebp = regs . ebp ;
child_tss . esp = regs . esp_if_crossRing ;
child_tss . esi = regs . esi ;
child_tss . edi = regs . edi ;
child_tss . eflags = regs . eflags ;
child_tss . eip = regs . eip ;
child_tss . cs = regs . cs ;
child_tss . ds = regs . ds ;
child_tss . es = regs . es ;
child_tss . fs = regs . fs ;
child_tss . gs = regs . gs ;
child_tss . ss = regs . ss_if_crossRing ;
2019-01-25 06:52:44 +00:00
2018-11-02 19:41:58 +00:00
# ifdef FORK_DEBUG
2019-03-23 21:03:17 +00:00
dbgprintf ( " fork: child will begin executing at %w:%x with stack %w:%x, kstack %w:%x \n " , child_tss . cs , child_tss . eip , child_tss . ss , child_tss . esp , child_tss . ss0 , child_tss . esp0 ) ;
2018-11-02 19:41:58 +00:00
# endif
2018-11-09 00:25:31 +00:00
{
InterruptDisabler disabler ;
g_processes - > prepend ( child ) ;
}
2018-11-02 19:41:58 +00:00
# ifdef TASK_DEBUG
2019-03-23 21:03:17 +00:00
kprintf ( " Process %u (%s) forked from %u @ %p \n " , child - > pid ( ) , child - > name ( ) . characters ( ) , m_pid , child_tss . eip ) ;
2018-11-02 19:41:58 +00:00
# endif
2019-03-23 21:03:17 +00:00
child - > main_thread ( ) . set_state ( Thread : : State : : Skip1SchedulerPass ) ;
2018-11-02 19:41:58 +00:00
return child ;
}
pid_t Process : : sys $ fork ( RegisterDump & regs )
{
auto * child = fork ( regs ) ;
ASSERT ( child ) ;
return child - > pid ( ) ;
}
2019-02-17 09:18:25 +00:00
int Process : : do_exec ( String path , Vector < String > arguments , Vector < String > environment )
2018-11-03 00:49:40 +00:00
{
2019-02-03 02:56:08 +00:00
ASSERT ( is_ring3 ( ) ) ;
2019-04-25 11:52:07 +00:00
dbgprintf ( " %s(%d) do_exec(%s): thread_count() = %d \n " , m_name . characters ( ) , m_pid , path . characters ( ) , thread_count ( ) ) ;
2019-03-23 21:03:17 +00:00
// FIXME(Thread): Kill any threads the moment we commit to the exec().
2019-04-23 20:17:01 +00:00
if ( thread_count ( ) ! = 1 ) {
dbgprintf ( " Gonna die because I have many threads! These are the threads: \n " ) ;
for_each_thread ( [ ] ( Thread & thread ) {
dbgprintf ( " Thread{%p}: TID=%d, PID=%d \n " , & thread , thread . tid ( ) , thread . pid ( ) ) ;
return IterationDecision : : Continue ;
} ) ;
ASSERT ( thread_count ( ) = = 1 ) ;
ASSERT_NOT_REACHED ( ) ;
}
2019-03-23 21:03:17 +00:00
2018-11-03 00:49:40 +00:00
auto parts = path . split ( ' / ' ) ;
2018-12-21 01:10:45 +00:00
if ( parts . is_empty ( ) )
2018-11-03 00:49:40 +00:00
return - ENOENT ;
2019-04-15 12:57:27 +00:00
auto result = VFS : : the ( ) . open ( path . view ( ) , 0 , 0 , cwd_inode ( ) ) ;
2019-03-06 21:14:31 +00:00
if ( result . is_error ( ) )
return result . error ( ) ;
auto descriptor = result . value ( ) ;
2018-11-03 00:49:40 +00:00
2019-01-31 16:31:23 +00:00
if ( ! descriptor - > metadata ( ) . may_execute ( m_euid , m_gids ) )
2018-11-03 00:49:40 +00:00
return - EACCES ;
2018-11-08 20:20:09 +00:00
if ( ! descriptor - > metadata ( ) . size ) {
return - ENOTIMPL ;
}
2018-11-03 00:49:40 +00:00
dword entry_eip = 0 ;
2018-12-31 13:58:03 +00:00
// FIXME: Is there a race here?
auto old_page_directory = move ( m_page_directory ) ;
2019-05-20 02:46:29 +00:00
m_page_directory = PageDirectory : : create_for_userspace ( ) ;
2018-11-09 00:25:31 +00:00
# ifdef MM_DEBUG
2018-12-31 13:58:03 +00:00
dbgprintf ( " Process %u exec: PD=%x created \n " , pid ( ) , m_page_directory . ptr ( ) ) ;
2018-11-09 00:25:31 +00:00
# endif
ProcessPagingScope paging_scope ( * this ) ;
2018-11-08 20:20:09 +00:00
2019-02-05 05:43:33 +00:00
auto vmo = VMObject : : create_file_backed ( descriptor - > inode ( ) ) ;
2019-02-26 23:02:01 +00:00
#if 0
// FIXME: I would like to do this, but it would instantiate all the damn inodes.
2019-01-22 04:01:00 +00:00
vmo - > set_name ( descriptor - > absolute_path ( ) ) ;
2019-02-26 23:02:01 +00:00
# else
vmo - > set_name ( " ELF image " ) ;
# endif
2019-02-10 11:42:54 +00:00
RetainPtr < Region > region = allocate_region_with_vmo ( LinearAddress ( ) , descriptor - > metadata ( ) . size , vmo . copy_ref ( ) , 0 , " executable " , true , false ) ;
2019-05-17 02:39:22 +00:00
ASSERT ( region ) ;
2019-01-22 04:01:00 +00:00
2019-03-27 03:01:15 +00:00
if ( this ! = & current - > process ( ) ) {
// FIXME: Don't force-load the entire executable at once, let the on-demand pager take care of it.
bool success = region - > page_in ( ) ;
ASSERT ( success ) ;
}
2019-05-16 15:18:25 +00:00
OwnPtr < ELFLoader > loader ;
2018-11-03 00:49:40 +00:00
{
// Okay, here comes the sleight of hand, pay close attention..
auto old_regions = move ( m_regions ) ;
2019-03-27 03:01:15 +00:00
m_regions . append ( * region ) ;
2019-05-16 15:18:25 +00:00
loader = make < ELFLoader > ( region - > laddr ( ) . as_ptr ( ) ) ;
loader - > map_section_hook = [ & ] ( LinearAddress laddr , size_t size , size_t alignment , size_t offset_in_image , bool is_readable , bool is_writable , const String & name ) {
2018-11-08 20:20:09 +00:00
ASSERT ( size ) ;
2018-11-09 09:03:21 +00:00
ASSERT ( alignment = = PAGE_SIZE ) ;
2019-01-31 16:31:23 +00:00
( void ) allocate_region_with_vmo ( laddr , size , vmo . copy_ref ( ) , offset_in_image , String ( name ) , is_readable , is_writable ) ;
2019-01-24 17:09:46 +00:00
return laddr . as_ptr ( ) ;
2018-11-08 20:20:09 +00:00
} ;
2019-05-16 15:18:25 +00:00
loader - > alloc_section_hook = [ & ] ( LinearAddress laddr , size_t size , size_t alignment , bool is_readable , bool is_writable , const String & name ) {
2018-11-03 10:28:23 +00:00
ASSERT ( size ) ;
2018-11-09 09:03:21 +00:00
ASSERT ( alignment = = PAGE_SIZE ) ;
2018-11-04 12:52:53 +00:00
( void ) allocate_region ( laddr , size , String ( name ) , is_readable , is_writable ) ;
2019-01-24 17:09:46 +00:00
return laddr . as_ptr ( ) ;
2018-11-03 00:49:40 +00:00
} ;
2019-05-16 15:18:25 +00:00
bool success = loader - > load ( ) ;
if ( ! success | | ! loader - > entry ( ) . get ( ) ) {
2018-12-31 13:58:03 +00:00
m_page_directory = move ( old_page_directory ) ;
2019-01-01 01:09:43 +00:00
// FIXME: RAII this somehow instead.
2019-03-23 21:03:17 +00:00
ASSERT ( & current - > process ( ) = = this ) ;
2018-11-03 01:04:36 +00:00
MM . enter_process_paging_scope ( * this ) ;
2018-11-03 00:49:40 +00:00
m_regions = move ( old_regions ) ;
2019-03-27 03:01:15 +00:00
kprintf ( " do_exec: Failure loading %s \n " , path . characters ( ) ) ;
2018-11-03 00:49:40 +00:00
return - ENOEXEC ;
}
2019-05-16 15:18:25 +00:00
entry_eip = loader - > entry ( ) . get ( ) ;
2018-11-03 00:49:40 +00:00
}
2019-05-16 15:18:25 +00:00
m_elf_loader = move ( loader ) ;
2019-05-14 10:06:09 +00:00
current - > m_kernel_stack_for_signal_handler_region = nullptr ;
2019-03-23 21:03:17 +00:00
current - > m_signal_stack_user_region = nullptr ;
current - > set_default_signal_dispositions ( ) ;
current - > m_signal_mask = 0 ;
current - > m_pending_signals = 0 ;
2018-11-10 22:29:07 +00:00
2019-02-25 21:06:55 +00:00
for ( int i = 0 ; i < m_fds . size ( ) ; + + i ) {
2018-11-13 00:36:31 +00:00
auto & daf = m_fds [ i ] ;
if ( daf . descriptor & & daf . flags & FD_CLOEXEC ) {
daf . descriptor - > close ( ) ;
daf = { } ;
}
}
2018-11-16 23:52:29 +00:00
// We cli() manually here because we don't want to get interrupted between do_exec() and Schedule::yield().
// The reason is that the task redirection we've set up above will be clobbered by the timer IRQ.
// If we used an InterruptDisabler that sti()'d on exit, we might timer tick'd too soon in exec().
2019-03-23 21:03:17 +00:00
if ( & current - > process ( ) = = this )
2019-02-06 16:28:14 +00:00
cli ( ) ;
2018-11-16 23:52:29 +00:00
2019-03-23 21:03:17 +00:00
Scheduler : : prepare_to_modify_tss ( main_thread ( ) ) ;
2018-11-03 00:49:40 +00:00
2019-01-19 21:53:05 +00:00
m_name = parts . take_last ( ) ;
2018-11-03 00:49:40 +00:00
2019-03-23 21:03:17 +00:00
// ss0 sp!!!!!!!!!
dword old_esp0 = main_thread ( ) . m_tss . esp0 ;
memset ( & main_thread ( ) . m_tss , 0 , sizeof ( main_thread ( ) . m_tss ) ) ;
main_thread ( ) . m_tss . eflags = 0x0202 ;
main_thread ( ) . m_tss . eip = entry_eip ;
main_thread ( ) . m_tss . cs = 0x1b ;
main_thread ( ) . m_tss . ds = 0x23 ;
main_thread ( ) . m_tss . es = 0x23 ;
main_thread ( ) . m_tss . fs = 0x23 ;
main_thread ( ) . m_tss . gs = 0x23 ;
main_thread ( ) . m_tss . ss = 0x23 ;
main_thread ( ) . m_tss . cr3 = page_directory ( ) . cr3 ( ) ;
2019-03-23 21:59:08 +00:00
main_thread ( ) . make_userspace_stack_for_main_thread ( move ( arguments ) , move ( environment ) ) ;
2019-03-23 21:03:17 +00:00
main_thread ( ) . m_tss . ss0 = 0x10 ;
main_thread ( ) . m_tss . esp0 = old_esp0 ;
main_thread ( ) . m_tss . ss2 = m_pid ;
2018-11-03 00:49:40 +00:00
2019-01-16 11:57:07 +00:00
m_executable = descriptor - > inode ( ) ;
2018-11-03 00:49:40 +00:00
2019-02-21 22:35:07 +00:00
if ( descriptor - > metadata ( ) . is_setuid ( ) )
m_euid = descriptor - > metadata ( ) . uid ;
if ( descriptor - > metadata ( ) . is_setgid ( ) )
m_egid = descriptor - > metadata ( ) . gid ;
2018-11-03 00:49:40 +00:00
# ifdef TASK_DEBUG
2019-03-23 21:03:17 +00:00
kprintf ( " Process %u (%s) exec'd %s @ %p \n " , pid ( ) , name ( ) . characters ( ) , path . characters ( ) , main_thread ( ) . tss ( ) . eip ) ;
2018-11-03 00:49:40 +00:00
# endif
2019-03-23 21:03:17 +00:00
main_thread ( ) . set_state ( Thread : : State : : Skip1SchedulerPass ) ;
2018-11-09 16:59:14 +00:00
return 0 ;
}
2019-02-17 09:18:25 +00:00
int Process : : exec ( String path , Vector < String > arguments , Vector < String > environment )
2018-11-09 16:59:14 +00:00
{
// The bulk of exec() is done by do_exec(), which ensures that all locals
// are cleaned up by the time we yield-teleport below.
2019-02-17 09:18:25 +00:00
int rc = do_exec ( move ( path ) , move ( arguments ) , move ( environment ) ) ;
2018-11-09 16:59:14 +00:00
if ( rc < 0 )
return rc ;
2018-11-07 22:13:38 +00:00
2019-03-23 21:03:17 +00:00
if ( & current - > process ( ) = = this ) {
2018-11-09 00:25:31 +00:00
Scheduler : : yield ( ) ;
2018-11-08 21:24:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-11-07 22:13:38 +00:00
}
2018-11-03 00:49:40 +00:00
return 0 ;
}
2018-11-03 09:20:23 +00:00
int Process : : sys $ execve ( const char * filename , const char * * argv , const char * * envp )
{
2019-02-17 09:18:25 +00:00
// NOTE: Be extremely careful with allocating any kernel memory in exec().
// On success, the kernel stack will be lost.
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( filename ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-26 01:16:26 +00:00
if ( ! * filename )
return - ENOENT ;
2018-11-03 09:20:23 +00:00
if ( argv ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( argv ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
for ( size_t i = 0 ; argv [ i ] ; + + i ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( argv [ i ] ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
}
}
if ( envp ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( envp ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
for ( size_t i = 0 ; envp [ i ] ; + + i ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( envp [ i ] ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-03 09:20:23 +00:00
}
}
String path ( filename ) ;
Vector < String > arguments ;
2019-02-17 09:18:25 +00:00
Vector < String > environment ;
{
auto parts = path . split ( ' / ' ) ;
if ( argv ) {
for ( size_t i = 0 ; argv [ i ] ; + + i ) {
arguments . append ( argv [ i ] ) ;
}
} else {
arguments . append ( parts . last ( ) ) ;
2018-11-03 09:20:23 +00:00
}
2019-02-17 09:18:25 +00:00
if ( envp ) {
for ( size_t i = 0 ; envp [ i ] ; + + i )
environment . append ( envp [ i ] ) ;
}
2018-11-03 09:20:23 +00:00
}
2019-02-17 09:18:25 +00:00
int rc = exec ( move ( path ) , move ( arguments ) , move ( environment ) ) ;
2018-11-07 22:13:38 +00:00
ASSERT ( rc < 0 ) ; // We should never continue after a successful exec!
2018-11-03 09:49:13 +00:00
return rc ;
2018-11-03 09:20:23 +00:00
}
2018-11-03 09:49:13 +00:00
Process * Process : : create_user_process ( const String & path , uid_t uid , gid_t gid , pid_t parent_pid , int & error , Vector < String > & & arguments , Vector < String > & & environment , TTY * tty )
2018-10-22 13:42:39 +00:00
{
2018-11-03 09:49:13 +00:00
// FIXME: Don't split() the path twice (sys$spawn also does it...)
2018-10-22 13:42:39 +00:00
auto parts = path . split ( ' / ' ) ;
2018-12-21 01:10:45 +00:00
if ( arguments . is_empty ( ) ) {
2018-11-03 09:49:13 +00:00
arguments . append ( parts . last ( ) ) ;
2018-10-25 10:06:00 +00:00
}
2019-01-16 11:57:07 +00:00
RetainPtr < Inode > cwd ;
2018-10-26 12:24:11 +00:00
{
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
if ( auto * parent = Process : : from_pid ( parent_pid ) )
2019-01-31 16:31:23 +00:00
cwd = parent - > m_cwd . copy_ref ( ) ;
2018-10-27 14:43:03 +00:00
}
2019-01-16 11:57:07 +00:00
2018-11-03 09:49:13 +00:00
if ( ! cwd )
2019-01-16 11:57:07 +00:00
cwd = VFS : : the ( ) . root_inode ( ) ;
2018-10-27 14:43:03 +00:00
2019-01-19 21:53:05 +00:00
auto * process = new Process ( parts . take_last ( ) , uid , gid , parent_pid , Ring3 , move ( cwd ) , nullptr , tty ) ;
2018-10-26 09:16:56 +00:00
2018-11-03 09:49:13 +00:00
error = process - > exec ( path , move ( arguments ) , move ( environment ) ) ;
2018-12-26 20:04:27 +00:00
if ( error ! = 0 ) {
delete process ;
2018-10-22 13:42:39 +00:00
return nullptr ;
2018-12-26 20:04:27 +00:00
}
2018-11-01 10:30:48 +00:00
2018-11-09 00:25:31 +00:00
{
InterruptDisabler disabler ;
g_processes - > prepend ( process ) ;
}
2018-10-23 22:20:34 +00:00
# ifdef TASK_DEBUG
2019-03-23 21:03:17 +00:00
kprintf ( " Process %u (%s) spawned @ %p \n " , process - > pid ( ) , process - > name ( ) . characters ( ) , process - > main_thread ( ) . tss ( ) . eip ) ;
2018-10-23 22:20:34 +00:00
# endif
2018-10-25 10:06:00 +00:00
error = 0 ;
2018-11-03 09:49:13 +00:00
return process ;
2018-10-22 13:42:39 +00:00
}
2018-12-24 22:10:48 +00:00
Process * Process : : create_kernel_process ( String & & name , void ( * e ) ( ) )
2018-10-25 09:15:17 +00:00
{
2018-11-01 13:41:49 +00:00
auto * process = new Process ( move ( name ) , ( uid_t ) 0 , ( gid_t ) 0 , ( pid_t ) 0 , Ring0 ) ;
2019-03-23 21:03:17 +00:00
process - > main_thread ( ) . tss ( ) . eip = ( dword ) e ;
2018-10-25 09:15:17 +00:00
2018-11-01 12:15:46 +00:00
if ( process - > pid ( ) ! = 0 ) {
2019-03-23 21:03:17 +00:00
InterruptDisabler disabler ;
g_processes - > prepend ( process ) ;
2018-10-25 09:15:17 +00:00
# ifdef TASK_DEBUG
2019-03-23 21:03:17 +00:00
kprintf ( " Kernel process %u (%s) spawned @ %p \n " , process - > pid ( ) , process - > name ( ) . characters ( ) , process - > main_thread ( ) . tss ( ) . eip ) ;
2018-10-25 09:15:17 +00:00
# endif
}
2019-03-23 21:03:17 +00:00
process - > main_thread ( ) . set_state ( Thread : : State : : Runnable ) ;
2018-11-01 12:15:46 +00:00
return process ;
2018-10-25 09:15:17 +00:00
}
2019-01-16 11:57:07 +00:00
Process : : Process ( String & & name , uid_t uid , gid_t gid , pid_t ppid , RingLevel ring , RetainPtr < Inode > & & cwd , RetainPtr < Inode > & & executable , TTY * tty , Process * fork_parent )
2018-10-22 13:42:39 +00:00
: m_name ( move ( name ) )
2018-11-02 19:41:58 +00:00
, m_pid ( next_pid + + ) // FIXME: RACE: This variable looks racy!
2018-10-22 13:42:39 +00:00
, m_uid ( uid )
, m_gid ( gid )
2018-11-05 14:04:19 +00:00
, m_euid ( uid )
, m_egid ( gid )
2018-10-25 09:15:17 +00:00
, m_ring ( ring )
2018-10-29 23:06:31 +00:00
, m_cwd ( move ( cwd ) )
2018-10-28 13:11:51 +00:00
, m_executable ( move ( executable ) )
2018-10-30 12:59:29 +00:00
, m_tty ( tty )
2018-11-06 12:33:06 +00:00
, m_ppid ( ppid )
2018-10-22 13:42:39 +00:00
{
2019-03-23 21:03:17 +00:00
dbgprintf ( " Process: New process PID=%u with name=%s \n " , m_pid , m_name . characters ( ) ) ;
2019-05-20 02:46:29 +00:00
m_page_directory = PageDirectory : : create_for_userspace ( ) ;
2019-03-23 21:03:17 +00:00
# ifdef MM_DEBUG
dbgprintf ( " Process %u ctor: PD=%x created \n " , pid ( ) , m_page_directory . ptr ( ) ) ;
# endif
2019-02-04 13:06:38 +00:00
2019-03-23 21:03:17 +00:00
// NOTE: fork() doesn't clone all threads; the thread that called fork() becomes the main thread in the new process.
if ( fork_parent )
m_main_thread = current - > clone ( * this ) ;
else
m_main_thread = new Thread ( * this ) ;
2019-01-25 06:52:44 +00:00
2018-11-07 00:38:51 +00:00
m_gids . set ( m_gid ) ;
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
m_sid = fork_parent - > m_sid ;
m_pgid = fork_parent - > m_pgid ;
} else {
2018-11-02 11:56:51 +00:00
// FIXME: Use a ProcessHandle? Presumably we're executing *IN* the parent right now though..
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
if ( auto * parent = Process : : from_pid ( m_ppid ) ) {
2018-11-02 11:56:51 +00:00
m_sid = parent - > m_sid ;
m_pgid = parent - > m_pgid ;
}
}
2018-11-02 19:41:58 +00:00
if ( fork_parent ) {
2018-11-13 00:36:31 +00:00
m_fds . resize ( fork_parent - > m_fds . size ( ) ) ;
2019-02-25 21:06:55 +00:00
for ( int i = 0 ; i < fork_parent - > m_fds . size ( ) ; + + i ) {
2018-11-13 00:36:31 +00:00
if ( ! fork_parent - > m_fds [ i ] . descriptor )
2018-11-02 19:41:58 +00:00
continue ;
# ifdef FORK_DEBUG
2018-12-29 02:28:55 +00:00
dbgprintf ( " fork: cloning fd %u... (%p) istty? %u \n " , i , fork_parent - > m_fds [ i ] . descriptor . ptr ( ) , fork_parent - > m_fds [ i ] . descriptor - > is_tty ( ) ) ;
2018-11-02 19:41:58 +00:00
# endif
2018-11-13 00:36:31 +00:00
m_fds [ i ] . descriptor = fork_parent - > m_fds [ i ] . descriptor - > clone ( ) ;
m_fds [ i ] . flags = fork_parent - > m_fds [ i ] . flags ;
2018-11-02 19:41:58 +00:00
}
} else {
2018-11-13 00:36:31 +00:00
m_fds . resize ( m_max_open_file_descriptors ) ;
2019-02-12 10:25:25 +00:00
auto & device_to_use_as_tty = tty ? ( CharacterDevice & ) * tty : NullDevice : : the ( ) ;
2019-03-06 21:14:31 +00:00
m_fds [ 0 ] . set ( * device_to_use_as_tty . open ( O_RDONLY ) . value ( ) ) ;
m_fds [ 1 ] . set ( * device_to_use_as_tty . open ( O_WRONLY ) . value ( ) ) ;
m_fds [ 2 ] . set ( * device_to_use_as_tty . open ( O_WRONLY ) . value ( ) ) ;
2018-10-16 09:01:38 +00:00
}
2019-02-22 01:39:13 +00:00
if ( fork_parent ) {
m_sid = fork_parent - > m_sid ;
m_pgid = fork_parent - > m_pgid ;
m_umask = fork_parent - > m_umask ;
}
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
Process : : ~ Process ( )
2018-10-16 09:01:38 +00:00
{
2019-03-24 00:20:35 +00:00
dbgprintf ( " ~Process{%p} name=%s pid=%d, m_fds=%d \n " , this , m_name . characters ( ) , pid ( ) , m_fds . size ( ) ) ;
2019-03-23 21:03:17 +00:00
delete m_main_thread ;
m_main_thread = nullptr ;
2019-04-23 20:17:01 +00:00
Vector < Thread * , 16 > my_threads ;
for_each_thread ( [ & my_threads ] ( auto & thread ) {
my_threads . append ( & thread ) ;
return IterationDecision : : Continue ;
} ) ;
for ( auto * thread : my_threads )
delete thread ;
2018-10-18 12:53:00 +00:00
}
2019-01-31 16:31:23 +00:00
void Process : : dump_regions ( )
2018-10-18 12:53:00 +00:00
{
2018-11-01 12:15:46 +00:00
kprintf ( " Process %s(%u) regions: \n " , name ( ) . characters ( ) , pid ( ) ) ;
2018-10-18 12:53:00 +00:00
kprintf ( " BEGIN END SIZE NAME \n " ) ;
for ( auto & region : m_regions ) {
kprintf ( " %x -- %x %x %s \n " ,
2019-01-24 17:09:46 +00:00
region - > laddr ( ) . get ( ) ,
region - > laddr ( ) . offset ( region - > size ( ) - 1 ) . get ( ) ,
region - > size ( ) ,
region - > name ( ) . characters ( ) ) ;
2018-10-18 12:53:00 +00:00
}
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
void Process : : sys $ exit ( int status )
2018-10-22 09:43:55 +00:00
{
cli ( ) ;
2018-10-23 22:20:34 +00:00
# ifdef TASK_DEBUG
2018-10-22 09:43:55 +00:00
kprintf ( " sys$exit: %s(%u) exit with status %d \n " , name ( ) . characters ( ) , pid ( ) , status ) ;
2018-10-23 22:20:34 +00:00
# endif
2018-10-22 09:43:55 +00:00
2019-05-16 11:41:16 +00:00
dump_backtrace ( ) ;
2019-05-06 19:48:48 +00:00
2018-11-07 17:30:59 +00:00
m_termination_status = status ;
m_termination_signal = 0 ;
2019-02-06 17:45:21 +00:00
die ( ) ;
2018-11-07 21:15:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-10-22 09:43:55 +00:00
}
2019-03-05 11:50:55 +00:00
void Process : : create_signal_trampolines_if_needed ( )
{
if ( ! m_return_to_ring3_from_signal_trampoline . is_null ( ) )
return ;
// FIXME: This should be a global trampoline shared by all processes, not one created per process!
// FIXME: Remap as read-only after setup.
auto * region = allocate_region ( LinearAddress ( ) , PAGE_SIZE , " Signal trampolines " , true , true ) ;
m_return_to_ring3_from_signal_trampoline = region - > laddr ( ) ;
byte * code_ptr = m_return_to_ring3_from_signal_trampoline . as_ptr ( ) ;
* code_ptr + + = 0x58 ; // pop eax (Argument to signal handler (ignored here))
* code_ptr + + = 0x5a ; // pop edx (Original signal mask to restore)
* code_ptr + + = 0xb8 ; // mov eax, <dword>
* ( dword * ) code_ptr = Syscall : : SC_restore_signal_mask ;
code_ptr + = sizeof ( dword ) ;
* code_ptr + + = 0xcd ; // int 0x82
* code_ptr + + = 0x82 ;
* code_ptr + + = 0x83 ; // add esp, (stack alignment padding)
* code_ptr + + = 0xc4 ;
* code_ptr + + = sizeof ( dword ) * 3 ;
* code_ptr + + = 0x61 ; // popa
* code_ptr + + = 0x9d ; // popf
* code_ptr + + = 0xc3 ; // ret
* code_ptr + + = 0x0f ; // ud2
* code_ptr + + = 0x0b ;
m_return_to_ring0_from_signal_trampoline = LinearAddress ( ( dword ) code_ptr ) ;
* code_ptr + + = 0x58 ; // pop eax (Argument to signal handler (ignored here))
* code_ptr + + = 0x5a ; // pop edx (Original signal mask to restore)
* code_ptr + + = 0xb8 ; // mov eax, <dword>
* ( dword * ) code_ptr = Syscall : : SC_restore_signal_mask ;
code_ptr + = sizeof ( dword ) ;
* code_ptr + + = 0xcd ; // int 0x82
// NOTE: Stack alignment padding doesn't matter when returning to ring0.
// Nothing matters really, as we're returning by replacing the entire TSS.
* code_ptr + + = 0x82 ;
* code_ptr + + = 0xb8 ; // mov eax, <dword>
* ( dword * ) code_ptr = Syscall : : SC_sigreturn ;
code_ptr + = sizeof ( dword ) ;
* code_ptr + + = 0xcd ; // int 0x82
* code_ptr + + = 0x82 ;
* code_ptr + + = 0x0f ; // ud2
* code_ptr + + = 0x0b ;
}
2019-03-05 09:34:08 +00:00
int Process : : sys $ restore_signal_mask ( dword mask )
{
2019-03-23 21:03:17 +00:00
current - > m_signal_mask = mask ;
2019-03-05 09:34:08 +00:00
return 0 ;
}
2018-11-07 20:19:47 +00:00
void Process : : sys $ sigreturn ( )
{
InterruptDisabler disabler ;
2019-03-23 21:03:17 +00:00
Scheduler : : prepare_to_modify_tss ( * current ) ;
2019-04-20 17:23:45 +00:00
current - > m_tss = * current - > m_tss_to_resume_kernel ;
current - > m_tss_to_resume_kernel . clear ( ) ;
2018-11-07 20:19:47 +00:00
# ifdef SIGNAL_DEBUG
2019-03-05 09:34:08 +00:00
kprintf ( " sys$sigreturn in %s(%u) \n " , name ( ) . characters ( ) , pid ( ) ) ;
2019-03-23 21:03:17 +00:00
auto & tss = current - > tss ( ) ;
kprintf ( " -> resuming execution at %w:%x stack %w:%x flags %x cr3 %x \n " , tss . cs , tss . eip , tss . ss , tss . esp , tss . eflags , tss . cr3 ) ;
2018-11-07 20:19:47 +00:00
# endif
2019-03-23 21:03:17 +00:00
current - > set_state ( Thread : : State : : Skip1SchedulerPass ) ;
2018-11-07 21:15:02 +00:00
Scheduler : : yield ( ) ;
2018-11-07 20:19:47 +00:00
kprintf ( " sys$sigreturn failed in %s(%u) \n " , name ( ) . characters ( ) , pid ( ) ) ;
ASSERT_NOT_REACHED ( ) ;
2018-11-06 09:46:40 +00:00
}
2018-11-07 17:30:59 +00:00
void Process : : crash ( )
2018-10-17 22:26:30 +00:00
{
2018-10-25 08:33:10 +00:00
ASSERT_INTERRUPTS_DISABLED ( ) ;
2019-03-23 21:03:17 +00:00
ASSERT ( ! is_dead ( ) ) ;
2019-03-13 22:14:30 +00:00
2019-05-16 17:49:48 +00:00
dump_backtrace ( ) ;
2018-11-07 17:30:59 +00:00
m_termination_signal = SIGSEGV ;
2019-01-31 16:31:23 +00:00
dump_regions ( ) ;
2019-02-08 08:45:53 +00:00
ASSERT ( is_ring3 ( ) ) ;
2019-01-30 17:26:19 +00:00
die ( ) ;
2018-11-07 21:15:02 +00:00
ASSERT_NOT_REACHED ( ) ;
2018-10-17 22:26:30 +00:00
}
2018-11-07 20:38:18 +00:00
Process * Process : : from_pid ( pid_t pid )
2018-10-16 09:01:38 +00:00
{
2018-10-26 13:11:29 +00:00
ASSERT_INTERRUPTS_DISABLED ( ) ;
2018-11-07 21:15:02 +00:00
for ( auto * process = g_processes - > head ( ) ; process ; process = process - > next ( ) ) {
2018-11-01 12:15:46 +00:00
if ( process - > pid ( ) = = pid )
return process ;
2018-10-16 09:01:38 +00:00
}
return nullptr ;
}
2018-11-07 10:37:54 +00:00
FileDescriptor * Process : : file_descriptor ( int fd )
2018-10-16 09:01:38 +00:00
{
if ( fd < 0 )
return nullptr ;
2019-02-25 21:06:55 +00:00
if ( fd < m_fds . size ( ) )
2018-11-13 00:36:31 +00:00
return m_fds [ fd ] . descriptor . ptr ( ) ;
2018-11-07 10:37:54 +00:00
return nullptr ;
}
const FileDescriptor * Process : : file_descriptor ( int fd ) const
{
if ( fd < 0 )
return nullptr ;
2019-02-25 21:06:55 +00:00
if ( fd < m_fds . size ( ) )
2018-11-13 00:36:31 +00:00
return m_fds [ fd ] . descriptor . ptr ( ) ;
2018-10-16 09:01:38 +00:00
return nullptr ;
}
2019-02-25 20:19:57 +00:00
ssize_t Process : : sys $ get_dir_entries ( int fd , void * buffer , ssize_t size )
2018-10-24 10:43:52 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
return descriptor - > get_dir_entries ( ( byte * ) buffer , size ) ;
2018-10-24 10:43:52 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ lseek ( int fd , off_t offset , int whence )
2018-10-16 09:01:38 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-31 16:50:43 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
return descriptor - > seek ( offset , whence ) ;
2018-10-16 09:01:38 +00:00
}
2019-02-25 20:19:57 +00:00
int Process : : sys $ ttyname_r ( int fd , char * buffer , ssize_t size )
2018-10-30 21:03:02 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-12-02 23:39:25 +00:00
if ( ! descriptor - > is_tty ( ) )
2018-10-30 21:03:02 +00:00
return - ENOTTY ;
2019-01-31 16:31:23 +00:00
auto tty_name = descriptor - > tty ( ) - > tty_name ( ) ;
if ( size < tty_name . length ( ) + 1 )
2018-10-30 21:03:02 +00:00
return - ERANGE ;
2019-01-31 16:31:23 +00:00
strcpy ( buffer , tty_name . characters ( ) ) ;
2018-10-30 21:03:02 +00:00
return 0 ;
}
2019-02-25 20:19:57 +00:00
int Process : : sys $ ptsname_r ( int fd , char * buffer , ssize_t size )
2019-01-15 05:30:19 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2019-01-15 05:30:19 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
auto * master_pty = descriptor - > master_pty ( ) ;
if ( ! master_pty )
return - ENOTTY ;
auto pts_name = master_pty - > pts_name ( ) ;
if ( size < pts_name . length ( ) + 1 )
return - ERANGE ;
strcpy ( buffer , pts_name . characters ( ) ) ;
return 0 ;
}
2019-05-10 01:19:25 +00:00
ssize_t Process : : sys $ writev ( int fd , const struct iovec * iov , int iov_count )
2018-10-30 14:33:37 +00:00
{
2019-05-10 01:19:25 +00:00
if ( iov_count < 0 )
2019-02-25 20:19:57 +00:00
return - EINVAL ;
2019-05-10 01:19:25 +00:00
if ( ! validate_read_typed ( iov , iov_count ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-05-10 01:19:25 +00:00
// FIXME: Return EINVAL if sum of iovecs is greater than INT_MAX
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 14:33:37 +00:00
return - EBADF ;
2019-05-10 01:19:25 +00:00
int nwritten = 0 ;
for ( int i = 0 ; i < iov_count ; + + i ) {
int rc = do_write ( * descriptor , ( const byte * ) iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
if ( rc < 0 ) {
if ( nwritten = = 0 )
return rc ;
return nwritten ;
}
nwritten + = rc ;
}
if ( current - > has_unmasked_pending_signals ( ) ) {
current - > block ( Thread : : State : : BlockedSignal ) ;
if ( nwritten = = 0 )
return - EINTR ;
}
return nwritten ;
}
ssize_t Process : : do_write ( FileDescriptor & descriptor , const byte * data , int data_size )
{
2018-11-12 00:28:46 +00:00
ssize_t nwritten = 0 ;
2019-05-19 08:25:05 +00:00
if ( ! descriptor . is_blocking ( ) ) {
if ( ! descriptor . can_write ( ) )
return - EAGAIN ;
}
2019-05-10 01:19:25 +00:00
while ( nwritten < data_size ) {
2018-11-12 00:28:46 +00:00
# ifdef IO_DEBUG
2019-05-10 01:19:25 +00:00
dbgprintf ( " while %u < %u \n " , nwritten , size ) ;
2018-11-12 00:28:46 +00:00
# endif
2019-05-10 01:19:25 +00:00
if ( ! descriptor . can_write ( ) ) {
2018-11-12 00:28:46 +00:00
# ifdef IO_DEBUG
2019-05-10 01:19:25 +00:00
dbgprintf ( " block write on %d \n " , fd ) ;
2018-11-12 00:28:46 +00:00
# endif
2019-05-10 01:19:25 +00:00
current - > block ( Thread : : State : : BlockedWrite , descriptor ) ;
}
ssize_t rc = descriptor . write ( data + nwritten , data_size - nwritten ) ;
2018-11-12 00:28:46 +00:00
# ifdef IO_DEBUG
2019-05-10 01:19:25 +00:00
dbgprintf ( " -> write returned %d \n " , rc ) ;
2018-11-12 00:28:46 +00:00
# endif
2019-05-10 01:19:25 +00:00
if ( rc < 0 ) {
// FIXME: Support returning partial nwritten with errno.
ASSERT ( nwritten = = 0 ) ;
return rc ;
2018-11-12 00:28:46 +00:00
}
2019-05-10 01:19:25 +00:00
if ( rc = = 0 )
break ;
if ( current - > has_unmasked_pending_signals ( ) ) {
current - > block ( Thread : : State : : BlockedSignal ) ;
if ( nwritten = = 0 )
return - EINTR ;
}
nwritten + = rc ;
2018-11-12 00:28:46 +00:00
}
2019-05-10 01:19:25 +00:00
return nwritten ;
}
ssize_t Process : : sys $ write ( int fd , const byte * data , ssize_t size )
{
if ( size < 0 )
return - EINVAL ;
if ( size = = 0 )
return 0 ;
if ( ! validate_read ( data , size ) )
return - EFAULT ;
# ifdef DEBUG_IO
dbgprintf ( " %s(%u): sys$write(%d, %p, %u) \n " , name ( ) . characters ( ) , pid ( ) , fd , data , size ) ;
# endif
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
auto nwritten = do_write ( * descriptor , data , size ) ;
2019-03-23 21:03:17 +00:00
if ( current - > has_unmasked_pending_signals ( ) ) {
current - > block ( Thread : : State : : BlockedSignal ) ;
2018-11-10 01:43:33 +00:00
if ( nwritten = = 0 )
return - EINTR ;
}
2018-10-30 14:33:37 +00:00
return nwritten ;
}
2019-02-25 20:19:57 +00:00
ssize_t Process : : sys $ read ( int fd , byte * buffer , ssize_t size )
2018-10-16 09:01:38 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2019-04-27 14:17:24 +00:00
if ( size = = 0 )
return 0 ;
2019-02-25 20:19:57 +00:00
if ( ! validate_write ( buffer , size ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-23 08:12:50 +00:00
# ifdef DEBUG_IO
2019-02-25 20:19:57 +00:00
dbgprintf ( " %s(%u) sys$read(%d, %p, %u) \n " , name ( ) . characters ( ) , pid ( ) , fd , buffer , size ) ;
2018-10-23 08:12:50 +00:00
# endif
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 14:33:37 +00:00
return - EBADF ;
2018-12-02 23:39:25 +00:00
if ( descriptor - > is_blocking ( ) ) {
2019-04-29 11:58:40 +00:00
if ( ! descriptor - > can_read ( ) ) {
2019-05-03 18:15:54 +00:00
current - > block ( Thread : : State : : BlockedRead , * descriptor ) ;
2019-03-23 21:03:17 +00:00
if ( current - > m_was_interrupted_while_blocked )
2018-11-07 20:19:47 +00:00
return - EINTR ;
2018-10-25 11:07:59 +00:00
}
}
2019-04-29 11:58:40 +00:00
return descriptor - > read ( buffer , size ) ;
2018-10-16 09:01:38 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ close ( int fd )
2018-10-16 09:01:38 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2018-11-07 10:37:54 +00:00
int rc = descriptor - > close ( ) ;
2018-11-13 00:36:31 +00:00
m_fds [ fd ] = { } ;
2018-11-01 13:00:28 +00:00
return rc ;
2018-10-16 09:01:38 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ utime ( const char * pathname , const utimbuf * buf )
2018-12-19 20:14:55 +00:00
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
if ( buf & & ! validate_read_typed ( buf ) )
return - EFAULT ;
2019-01-23 05:53:01 +00:00
time_t atime ;
time_t mtime ;
2018-12-19 20:14:55 +00:00
if ( buf ) {
atime = buf - > actime ;
mtime = buf - > modtime ;
} else {
2019-03-25 01:06:57 +00:00
struct timeval now ;
kgettimeofday ( now ) ;
mtime = now . tv_sec ;
atime = now . tv_sec ;
2018-12-19 20:14:55 +00:00
}
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . utime ( StringView ( pathname ) , cwd_inode ( ) , atime , mtime ) ;
2018-12-19 20:14:55 +00:00
}
2018-11-10 23:20:53 +00:00
int Process : : sys $ access ( const char * pathname , int mode )
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( pathname ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . access ( StringView ( pathname ) , mode , cwd_inode ( ) ) ;
2018-11-10 23:20:53 +00:00
}
2018-11-11 14:36:40 +00:00
int Process : : sys $ fcntl ( int fd , int cmd , dword arg )
2018-11-11 09:38:33 +00:00
{
( void ) cmd ;
2018-11-11 14:36:40 +00:00
( void ) arg ;
dbgprintf ( " sys$fcntl: fd=%d, cmd=%d, arg=%u \n " , fd , cmd , arg ) ;
2018-11-11 09:38:33 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
2018-11-13 00:36:31 +00:00
// NOTE: The FD flags are not shared between FileDescriptor objects.
// This means that dup() doesn't copy the FD_CLOEXEC flag!
2018-11-11 14:36:40 +00:00
switch ( cmd ) {
2018-11-16 21:14:40 +00:00
case F_DUPFD : {
int arg_fd = ( int ) arg ;
if ( arg_fd < 0 )
return - EINVAL ;
2019-04-06 12:54:32 +00:00
int new_fd = alloc_fd ( arg_fd ) ;
if ( new_fd < 0 )
return new_fd ;
2019-03-06 21:14:31 +00:00
m_fds [ new_fd ] . set ( * descriptor ) ;
2018-11-16 21:14:40 +00:00
break ;
}
2018-11-11 14:36:40 +00:00
case F_GETFD :
2018-11-13 00:36:31 +00:00
return m_fds [ fd ] . flags ;
2018-11-11 14:36:40 +00:00
case F_SETFD :
2018-11-13 00:36:31 +00:00
m_fds [ fd ] . flags = arg ;
break ;
2018-11-11 14:36:40 +00:00
case F_GETFL :
return descriptor - > file_flags ( ) ;
case F_SETFL :
2019-01-15 05:49:52 +00:00
// FIXME: Support changing O_NONBLOCK
2018-11-13 00:36:31 +00:00
descriptor - > set_file_flags ( arg ) ;
break ;
2018-11-11 14:36:40 +00:00
default :
ASSERT_NOT_REACHED ( ) ;
}
return 0 ;
2018-11-11 09:38:33 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ fstat ( int fd , stat * statbuf )
2018-11-10 23:20:53 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-10 23:20:53 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
2019-03-01 23:11:08 +00:00
return descriptor - > fstat ( * statbuf ) ;
2018-11-10 23:20:53 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ lstat ( const char * path , stat * statbuf )
2018-10-24 11:19:36 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . stat ( StringView ( path ) , O_NOFOLLOW_NOERROR , cwd_inode ( ) , * statbuf ) ;
2018-10-24 11:19:36 +00:00
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ stat ( const char * path , stat * statbuf )
2018-10-31 09:14:56 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( statbuf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . stat ( StringView ( path ) , O_NOFOLLOW_NOERROR , cwd_inode ( ) , * statbuf ) ;
2018-10-31 09:14:56 +00:00
}
2019-02-25 20:19:57 +00:00
int Process : : sys $ readlink ( const char * path , char * buffer , ssize_t size )
2018-10-28 13:11:51 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2018-10-28 13:11:51 +00:00
2019-03-06 21:14:31 +00:00
auto result = VFS : : the ( ) . open ( path , O_RDONLY | O_NOFOLLOW_NOERROR , 0 , cwd_inode ( ) ) ;
if ( result . is_error ( ) )
return result . error ( ) ;
auto descriptor = result . value ( ) ;
2018-10-28 13:11:51 +00:00
2019-01-31 16:31:23 +00:00
if ( ! descriptor - > metadata ( ) . is_symlink ( ) )
2018-10-28 13:11:51 +00:00
return - EINVAL ;
2019-04-29 11:58:40 +00:00
auto contents = descriptor - > read_entire_file ( ) ;
2018-10-28 13:11:51 +00:00
if ( ! contents )
return - EIO ; // FIXME: Get a more detailed error from VFS.
2019-02-25 20:19:57 +00:00
memcpy ( buffer , contents . pointer ( ) , min ( size , ( ssize_t ) contents . size ( ) ) ) ;
2018-10-28 13:11:51 +00:00
if ( contents . size ( ) + 1 < size )
buffer [ contents . size ( ) ] = ' \0 ' ;
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ chdir ( const char * path )
2018-10-24 12:28:22 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-15 12:57:27 +00:00
auto directory_or_error = VFS : : the ( ) . open_directory ( StringView ( path ) , cwd_inode ( ) ) ;
2019-03-01 22:54:07 +00:00
if ( directory_or_error . is_error ( ) )
return directory_or_error . error ( ) ;
m_cwd = * directory_or_error . value ( ) ;
2018-10-24 12:28:22 +00:00
return 0 ;
}
2019-02-25 20:19:57 +00:00
int Process : : sys $ getcwd ( char * buffer , ssize_t size )
2018-10-26 12:24:11 +00:00
{
2019-02-25 20:19:57 +00:00
if ( size < 0 )
return - EINVAL ;
2018-11-16 15:10:59 +00:00
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
2019-03-06 21:30:13 +00:00
auto path_or_error = VFS : : the ( ) . absolute_path ( cwd_inode ( ) ) ;
if ( path_or_error . is_error ( ) )
return path_or_error . error ( ) ;
auto path = path_or_error . value ( ) ;
2018-10-29 23:06:31 +00:00
if ( size < path . length ( ) + 1 )
return - ERANGE ;
strcpy ( buffer , path . characters ( ) ) ;
2018-11-11 14:36:40 +00:00
return 0 ;
2018-10-26 12:24:11 +00:00
}
2019-03-06 21:30:13 +00:00
int Process : : number_of_open_file_descriptors ( ) const
2018-11-01 12:39:28 +00:00
{
2019-03-06 21:30:13 +00:00
int count = 0 ;
2018-11-13 00:36:31 +00:00
for ( auto & descriptor : m_fds ) {
2018-11-07 10:37:54 +00:00
if ( descriptor )
2018-11-01 12:39:28 +00:00
+ + count ;
}
return count ;
}
2019-01-21 23:58:13 +00:00
int Process : : sys $ open ( const char * path , int options , mode_t mode )
2018-10-16 09:01:38 +00:00
{
2018-10-23 08:12:50 +00:00
# ifdef DEBUG_IO
2018-11-11 14:36:40 +00:00
dbgprintf ( " %s(%u) sys$open( \" %s \" ) \n " , name ( ) . characters ( ) , pid ( ) , path ) ;
2018-10-23 08:12:50 +00:00
# endif
2018-11-16 15:23:39 +00:00
if ( ! validate_read_str ( path ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-04-06 12:54:32 +00:00
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
2019-03-06 21:14:31 +00:00
auto result = VFS : : the ( ) . open ( path , options , mode & ~ umask ( ) , cwd_inode ( ) ) ;
if ( result . is_error ( ) )
return result . error ( ) ;
auto descriptor = result . value ( ) ;
2018-12-02 23:39:25 +00:00
if ( options & O_DIRECTORY & & ! descriptor - > is_directory ( ) )
2018-10-28 13:11:51 +00:00
return - ENOTDIR ; // FIXME: This should be handled by VFS::open.
2019-01-15 05:49:52 +00:00
if ( options & O_NONBLOCK )
descriptor - > set_blocking ( false ) ;
2018-11-13 00:36:31 +00:00
dword flags = ( options & O_CLOEXEC ) ? FD_CLOEXEC : 0 ;
m_fds [ fd ] . set ( move ( descriptor ) , flags ) ;
2018-10-26 12:30:13 +00:00
return fd ;
2018-10-16 09:01:38 +00:00
}
2019-04-06 12:54:32 +00:00
int Process : : alloc_fd ( int first_candidate_fd )
2018-11-12 00:28:46 +00:00
{
2019-04-06 12:54:32 +00:00
int fd = - EMFILE ;
for ( int i = first_candidate_fd ; i < ( int ) m_max_open_file_descriptors ; + + i ) {
2018-11-13 00:36:31 +00:00
if ( ! m_fds [ i ] ) {
2018-11-12 00:28:46 +00:00
fd = i ;
break ;
}
}
return fd ;
}
2018-11-16 15:23:39 +00:00
int Process : : sys $ pipe ( int pipefd [ 2 ] )
2018-11-10 23:20:53 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( pipefd ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-12 00:28:46 +00:00
if ( number_of_open_file_descriptors ( ) + 2 > max_open_file_descriptors ( ) )
return - EMFILE ;
2019-04-25 11:52:07 +00:00
auto fifo = FIFO : : create ( m_uid ) ;
2018-11-12 00:28:46 +00:00
int reader_fd = alloc_fd ( ) ;
2019-05-18 02:14:22 +00:00
m_fds [ reader_fd ] . set ( fifo - > open_direction ( FIFO : : Direction : : Reader ) ) ;
2018-11-12 00:28:46 +00:00
pipefd [ 0 ] = reader_fd ;
int writer_fd = alloc_fd ( ) ;
2019-05-18 02:14:22 +00:00
m_fds [ writer_fd ] . set ( fifo - > open_direction ( FIFO : : Direction : : Writer ) ) ;
2018-11-12 00:28:46 +00:00
pipefd [ 1 ] = writer_fd ;
return 0 ;
2018-11-10 23:20:53 +00:00
}
int Process : : sys $ killpg ( int pgrp , int signum )
{
if ( signum < 1 | | signum > = 32 )
return - EINVAL ;
( void ) pgrp ;
ASSERT_NOT_REACHED ( ) ;
}
2019-02-21 22:35:07 +00:00
int Process : : sys $ setuid ( uid_t uid )
2018-11-10 23:20:53 +00:00
{
2019-02-21 22:35:07 +00:00
if ( uid ! = m_uid & & ! is_superuser ( ) )
return - EPERM ;
m_uid = uid ;
m_euid = uid ;
return 0 ;
2018-11-10 23:20:53 +00:00
}
2019-02-21 22:35:07 +00:00
int Process : : sys $ setgid ( gid_t gid )
2018-11-10 23:20:53 +00:00
{
2019-02-21 22:35:07 +00:00
if ( gid ! = m_gid & & ! is_superuser ( ) )
return - EPERM ;
m_gid = gid ;
m_egid = gid ;
return 0 ;
2018-11-10 23:20:53 +00:00
}
unsigned Process : : sys $ alarm ( unsigned seconds )
{
( void ) seconds ;
ASSERT_NOT_REACHED ( ) ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ uname ( utsname * buf )
2018-10-26 12:56:21 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( buf ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-26 12:56:21 +00:00
strcpy ( buf - > sysname , " Serenity " ) ;
strcpy ( buf - > release , " 1.0-dev " ) ;
strcpy ( buf - > version , " FIXME " ) ;
strcpy ( buf - > machine , " i386 " ) ;
2019-02-07 09:29:26 +00:00
LOCKER ( * s_hostname_lock ) ;
strncpy ( buf - > nodename , s_hostname - > characters ( ) , sizeof ( utsname : : nodename ) ) ;
2018-10-26 12:56:21 +00:00
return 0 ;
}
2018-11-05 17:16:00 +00:00
int Process : : sys $ isatty ( int fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-11-05 17:16:00 +00:00
return - EBADF ;
2018-12-02 23:39:25 +00:00
if ( ! descriptor - > is_tty ( ) )
2018-11-05 17:16:00 +00:00
return - ENOTTY ;
return 1 ;
}
2018-11-02 13:06:48 +00:00
int Process : : sys $ kill ( pid_t pid , int signal )
2018-10-16 09:01:38 +00:00
{
2019-02-28 10:45:45 +00:00
if ( signal < 0 | | signal > = 32 )
return - EINVAL ;
2018-10-16 09:01:38 +00:00
if ( pid = = 0 ) {
// FIXME: Send to same-group processes.
ASSERT ( pid ! = 0 ) ;
}
if ( pid = = - 1 ) {
// FIXME: Send to all processes.
ASSERT ( pid ! = - 1 ) ;
}
2019-02-28 08:44:48 +00:00
if ( pid = = m_pid ) {
2019-03-23 21:03:17 +00:00
current - > send_signal ( signal , this ) ;
2019-02-28 08:44:48 +00:00
Scheduler : : yield ( ) ;
return 0 ;
}
2019-02-28 10:45:45 +00:00
InterruptDisabler disabler ;
auto * peer = Process : : from_pid ( pid ) ;
2018-10-31 00:06:57 +00:00
if ( ! peer )
return - ESRCH ;
2019-02-28 10:45:45 +00:00
// FIXME: Allow sending SIGCONT to everyone in the process group.
// FIXME: Should setuid processes have some special treatment here?
if ( ! is_superuser ( ) & & m_euid ! = peer - > m_uid & & m_uid ! = peer - > m_uid )
return - EPERM ;
if ( peer - > is_ring0 ( ) & & signal = = SIGKILL ) {
kprintf ( " %s(%u) attempted to send SIGKILL to ring 0 process %s(%u) \n " , name ( ) . characters ( ) , m_pid , peer - > name ( ) . characters ( ) , peer - > pid ( ) ) ;
return - EPERM ;
}
2018-11-02 13:06:48 +00:00
peer - > send_signal ( signal , this ) ;
return 0 ;
2018-10-16 09:01:38 +00:00
}
2019-02-03 15:11:28 +00:00
int Process : : sys $ usleep ( useconds_t usec )
{
if ( ! usec )
return 0 ;
2019-03-24 00:52:10 +00:00
current - > sleep ( usec / 1000 ) ;
2019-04-13 23:29:14 +00:00
if ( current - > m_wakeup_time > g_uptime ) {
2019-03-23 21:03:17 +00:00
ASSERT ( current - > m_was_interrupted_while_blocked ) ;
2019-04-13 23:29:14 +00:00
dword ticks_left_until_original_wakeup_time = current - > m_wakeup_time - g_uptime ;
2019-02-03 15:11:28 +00:00
return ticks_left_until_original_wakeup_time / TICKS_PER_SECOND ;
}
return 0 ;
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ sleep ( unsigned seconds )
2018-10-25 11:53:49 +00:00
{
if ( ! seconds )
return 0 ;
2019-03-24 00:52:10 +00:00
current - > sleep ( seconds * TICKS_PER_SECOND ) ;
2019-04-13 23:29:14 +00:00
if ( current - > m_wakeup_time > g_uptime ) {
2019-03-23 21:03:17 +00:00
ASSERT ( current - > m_was_interrupted_while_blocked ) ;
2019-04-13 23:29:14 +00:00
dword ticks_left_until_original_wakeup_time = current - > m_wakeup_time - g_uptime ;
2018-11-07 20:19:47 +00:00
return ticks_left_until_original_wakeup_time / TICKS_PER_SECOND ;
}
2018-10-25 11:53:49 +00:00
return 0 ;
}
2019-03-13 12:13:23 +00:00
void kgettimeofday ( timeval & tv )
{
2019-03-25 01:06:57 +00:00
tv . tv_sec = RTC : : boot_time ( ) + PIT : : seconds_since_boot ( ) ;
tv . tv_usec = PIT : : ticks_this_second ( ) * 1000 ;
2019-03-13 12:13:23 +00:00
}
2018-11-01 12:15:46 +00:00
int Process : : sys $ gettimeofday ( timeval * tv )
2018-10-25 15:29:49 +00:00
{
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( tv ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-03-13 12:13:23 +00:00
kgettimeofday ( * tv ) ;
2018-10-25 15:29:49 +00:00
return 0 ;
}
2018-11-01 12:15:46 +00:00
uid_t Process : : sys $ getuid ( )
2018-10-16 09:01:38 +00:00
{
return m_uid ;
}
2018-11-01 12:15:46 +00:00
gid_t Process : : sys $ getgid ( )
2018-10-22 11:55:11 +00:00
{
return m_gid ;
}
2018-11-05 14:04:19 +00:00
uid_t Process : : sys $ geteuid ( )
{
return m_euid ;
}
gid_t Process : : sys $ getegid ( )
{
return m_egid ;
}
2018-11-01 12:15:46 +00:00
pid_t Process : : sys $ getpid ( )
2018-10-22 11:55:11 +00:00
{
return m_pid ;
}
2018-11-06 12:33:06 +00:00
pid_t Process : : sys $ getppid ( )
{
return m_ppid ;
}
2018-11-06 12:40:23 +00:00
mode_t Process : : sys $ umask ( mode_t mask )
{
auto old_mask = m_umask ;
2019-02-22 01:39:13 +00:00
m_umask = mask & 0777 ;
2018-11-06 12:40:23 +00:00
return old_mask ;
}
2018-11-28 21:01:24 +00:00
int Process : : reap ( Process & process )
2018-11-07 22:59:49 +00:00
{
2019-03-27 13:38:32 +00:00
int exit_status ;
{
InterruptDisabler disabler ;
exit_status = ( process . m_termination_status < < 8 ) | process . m_termination_signal ;
2018-12-03 00:12:26 +00:00
2019-03-27 13:38:32 +00:00
if ( process . ppid ( ) ) {
auto * parent = Process : : from_pid ( process . ppid ( ) ) ;
if ( parent ) {
parent - > m_ticks_in_user_for_dead_children + = process . m_ticks_in_user + process . m_ticks_in_user_for_dead_children ;
parent - > m_ticks_in_kernel_for_dead_children + = process . m_ticks_in_kernel + process . m_ticks_in_kernel_for_dead_children ;
}
2019-01-30 18:35:38 +00:00
}
2018-12-03 00:12:26 +00:00
2019-03-27 13:38:32 +00:00
dbgprintf ( " reap: %s(%u) {%s} \n " , process . name ( ) . characters ( ) , process . pid ( ) , to_string ( process . state ( ) ) ) ;
ASSERT ( process . is_dead ( ) ) ;
g_processes - > remove ( & process ) ;
}
2018-11-09 00:25:31 +00:00
delete & process ;
2018-11-28 21:01:24 +00:00
return exit_status ;
2018-11-07 22:59:49 +00:00
}
2018-11-01 12:15:46 +00:00
pid_t Process : : sys $ waitpid ( pid_t waitee , int * wstatus , int options )
2018-10-23 22:20:34 +00:00
{
2018-11-16 23:11:08 +00:00
dbgprintf ( " sys$waitpid(%d, %p, %d) \n " , waitee , wstatus , options ) ;
2018-11-09 09:03:21 +00:00
// FIXME: Respect options
( void ) options ;
2018-10-26 23:24:22 +00:00
if ( wstatus )
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( wstatus ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-10-26 23:24:22 +00:00
2018-11-28 21:01:24 +00:00
int dummy_wstatus ;
int & exit_status = wstatus ? * wstatus : dummy_wstatus ;
2018-11-07 22:59:49 +00:00
{
InterruptDisabler disabler ;
2018-11-11 14:36:40 +00:00
if ( waitee ! = - 1 & & ! Process : : from_pid ( waitee ) )
2018-11-07 22:59:49 +00:00
return - ECHILD ;
}
2018-11-16 23:11:08 +00:00
if ( options & WNOHANG ) {
if ( waitee = = - 1 ) {
pid_t reaped_pid = 0 ;
InterruptDisabler disabler ;
2018-11-28 21:01:24 +00:00
for_each_child ( [ & reaped_pid , & exit_status ] ( Process & process ) {
2019-03-23 21:03:17 +00:00
if ( process . is_dead ( ) ) {
2018-11-16 23:11:08 +00:00
reaped_pid = process . pid ( ) ;
2018-11-28 21:01:24 +00:00
exit_status = reap ( process ) ;
2018-11-16 23:11:08 +00:00
}
return true ;
} ) ;
return reaped_pid ;
} else {
2019-02-04 13:06:38 +00:00
ASSERT ( waitee > 0 ) ; // FIXME: Implement other PID specs.
2019-02-26 23:02:01 +00:00
InterruptDisabler disabler ;
2018-11-16 23:11:08 +00:00
auto * waitee_process = Process : : from_pid ( waitee ) ;
if ( ! waitee_process )
return - ECHILD ;
2019-03-23 21:03:17 +00:00
if ( waitee_process - > is_dead ( ) ) {
2018-11-28 21:01:24 +00:00
exit_status = reap ( * waitee_process ) ;
2018-11-16 23:11:08 +00:00
return waitee ;
}
return 0 ;
}
}
2019-03-23 21:03:17 +00:00
current - > m_waitee_pid = waitee ;
current - > block ( Thread : : State : : BlockedWait ) ;
if ( current - > m_was_interrupted_while_blocked )
2018-11-07 20:19:47 +00:00
return - EINTR ;
2018-11-09 00:25:31 +00:00
Process * waitee_process ;
{
InterruptDisabler disabler ;
2018-11-11 14:36:40 +00:00
// NOTE: If waitee was -1, m_waitee will have been filled in by the scheduler.
2019-03-23 21:03:17 +00:00
waitee_process = Process : : from_pid ( current - > m_waitee_pid ) ;
2018-11-09 00:25:31 +00:00
}
ASSERT ( waitee_process ) ;
2018-11-28 21:01:24 +00:00
exit_status = reap ( * waitee_process ) ;
2019-03-23 21:03:17 +00:00
return current - > m_waitee_pid ;
2018-10-16 09:01:38 +00:00
}
2019-02-11 05:03:30 +00:00
enum class KernelMemoryCheckResult {
NotInsideKernelMemory ,
AccessGranted ,
AccessDenied
} ;
2019-05-18 01:06:34 +00:00
// FIXME: Nothing about this is really super...
// This structure is only present at offset 28 in the main multiboot info struct
// if bit 5 of offset 0 (flags) is set. We're just assuming that the flag is set.
//
// Also, there's almost certainly a better way to get that information here than
// a global set by boot.S
//
// Also I'm not 100% sure any of this is correct...
struct mb_elf {
uint32_t num ;
uint32_t size ;
uint32_t addr ;
uint32_t shndx ;
} ;
extern " C " {
void * multiboot_ptr ;
}
2019-02-11 05:03:30 +00:00
static KernelMemoryCheckResult check_kernel_memory_access ( LinearAddress laddr , bool is_write )
2019-01-27 09:17:56 +00:00
{
2019-05-18 01:06:34 +00:00
// FIXME: It would be better to have a proper structure for this...
auto * sections = ( const mb_elf * ) ( ( const byte * ) multiboot_ptr + 28 ) ;
auto * kernel_program_headers = ( Elf32_Phdr * ) ( sections - > addr ) ;
for ( unsigned i = 0 ; i < sections - > num ; + + i ) {
2019-02-06 16:28:14 +00:00
auto & segment = kernel_program_headers [ i ] ;
2019-02-11 05:03:30 +00:00
if ( segment . p_type ! = PT_LOAD | | ! segment . p_vaddr | | ! segment . p_memsz )
continue ;
2019-02-06 16:28:14 +00:00
if ( laddr . get ( ) < segment . p_vaddr | | laddr . get ( ) > ( segment . p_vaddr + segment . p_memsz ) )
continue ;
if ( is_write & & ! ( kernel_program_headers [ i ] . p_flags & PF_W ) )
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : AccessDenied ;
2019-02-06 16:28:14 +00:00
if ( ! is_write & & ! ( kernel_program_headers [ i ] . p_flags & PF_R ) )
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : AccessDenied ;
return KernelMemoryCheckResult : : AccessGranted ;
2019-02-06 16:28:14 +00:00
}
2019-02-11 05:03:30 +00:00
return KernelMemoryCheckResult : : NotInsideKernelMemory ;
2019-01-27 09:17:56 +00:00
}
2019-01-01 01:20:01 +00:00
bool Process : : validate_read_from_kernel ( LinearAddress laddr ) const
2018-10-26 22:14:24 +00:00
{
2019-04-15 21:48:31 +00:00
if ( laddr . is_null ( ) )
return false ;
2018-11-01 11:45:51 +00:00
// We check extra carefully here since the first 4MB of the address space is identity-mapped.
// This code allows access outside of the known used address ranges to get caught.
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( laddr , false ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2018-10-26 22:14:24 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-24 17:09:46 +00:00
if ( is_kmalloc_address ( laddr . as_ptr ( ) ) )
2018-10-26 22:14:24 +00:00
return true ;
2019-01-24 17:09:46 +00:00
return validate_read ( laddr . as_ptr ( ) , 1 ) ;
2018-10-26 22:14:24 +00:00
}
2019-02-07 23:10:01 +00:00
bool Process : : validate_read_str ( const char * str )
{
if ( ! validate_read ( str , 1 ) )
return false ;
return validate_read ( str , strlen ( str ) + 1 ) ;
}
2019-02-25 20:19:57 +00:00
bool Process : : validate_read ( const void * address , ssize_t size ) const
2018-11-16 14:41:48 +00:00
{
2019-02-25 20:19:57 +00:00
ASSERT ( size > = 0 ) ;
2019-02-11 05:03:30 +00:00
LinearAddress first_address ( ( dword ) address ) ;
LinearAddress last_address = first_address . offset ( size - 1 ) ;
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( first_address , false ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2019-01-27 09:17:56 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-27 09:17:56 +00:00
if ( is_kmalloc_address ( address ) )
return true ;
}
2019-01-25 00:39:15 +00:00
ASSERT ( size ) ;
if ( ! size )
return false ;
if ( first_address . page_base ( ) ! = last_address . page_base ( ) ) {
if ( ! MM . validate_user_read ( * this , last_address ) )
2018-11-16 14:41:48 +00:00
return false ;
}
2019-01-25 00:39:15 +00:00
return MM . validate_user_read ( * this , first_address ) ;
2018-11-16 14:41:48 +00:00
}
2019-02-25 20:19:57 +00:00
bool Process : : validate_write ( void * address , ssize_t size ) const
2018-11-16 14:41:48 +00:00
{
2019-02-25 20:19:57 +00:00
ASSERT ( size > = 0 ) ;
2019-02-11 05:03:30 +00:00
LinearAddress first_address ( ( dword ) address ) ;
LinearAddress last_address = first_address . offset ( size - 1 ) ;
2019-01-31 16:31:23 +00:00
if ( is_ring0 ( ) ) {
2019-01-27 09:17:56 +00:00
if ( is_kmalloc_address ( address ) )
return true ;
2019-02-11 05:03:30 +00:00
auto kmc_result = check_kernel_memory_access ( first_address , true ) ;
if ( kmc_result = = KernelMemoryCheckResult : : AccessGranted )
2019-02-06 16:28:14 +00:00
return true ;
2019-02-11 05:03:30 +00:00
if ( kmc_result = = KernelMemoryCheckResult : : AccessDenied )
return false ;
2019-01-27 09:17:56 +00:00
}
2019-01-25 00:39:15 +00:00
if ( ! size )
return false ;
if ( first_address . page_base ( ) ! = last_address . page_base ( ) ) {
if ( ! MM . validate_user_write ( * this , last_address ) )
2018-11-16 14:41:48 +00:00
return false ;
}
2019-01-25 00:39:15 +00:00
return MM . validate_user_write ( * this , last_address ) ;
2018-11-16 14:41:48 +00:00
}
2018-11-02 11:56:51 +00:00
pid_t Process : : sys $ getsid ( pid_t pid )
{
if ( pid = = 0 )
return m_sid ;
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
if ( m_sid ! = process - > m_sid )
return - EPERM ;
return process - > m_sid ;
}
pid_t Process : : sys $ setsid ( )
{
InterruptDisabler disabler ;
bool found_process_with_same_pgid_as_my_pid = false ;
2018-11-08 20:20:09 +00:00
Process : : for_each_in_pgrp ( pid ( ) , [ & ] ( auto & ) {
2018-11-07 20:38:18 +00:00
found_process_with_same_pgid_as_my_pid = true ;
return false ;
2018-11-02 11:56:51 +00:00
} ) ;
if ( found_process_with_same_pgid_as_my_pid )
return - EPERM ;
m_sid = m_pid ;
m_pgid = m_pid ;
return m_sid ;
}
pid_t Process : : sys $ getpgid ( pid_t pid )
{
if ( pid = = 0 )
return m_pgid ;
InterruptDisabler disabler ; // FIXME: Use a ProcessHandle
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
return process - > m_pgid ;
}
pid_t Process : : sys $ getpgrp ( )
{
return m_pgid ;
}
static pid_t get_sid_from_pgid ( pid_t pgid )
{
InterruptDisabler disabler ;
2018-11-07 20:38:18 +00:00
auto * group_leader = Process : : from_pid ( pgid ) ;
2018-11-02 11:56:51 +00:00
if ( ! group_leader )
return - 1 ;
return group_leader - > sid ( ) ;
}
int Process : : sys $ setpgid ( pid_t specified_pid , pid_t specified_pgid )
{
InterruptDisabler disabler ; // FIXME: Use a ProcessHandle
pid_t pid = specified_pid ? specified_pid : m_pid ;
if ( specified_pgid < 0 )
return - EINVAL ;
2018-11-07 20:38:18 +00:00
auto * process = Process : : from_pid ( pid ) ;
2018-11-02 11:56:51 +00:00
if ( ! process )
return - ESRCH ;
pid_t new_pgid = specified_pgid ? specified_pgid : process - > m_pid ;
pid_t current_sid = get_sid_from_pgid ( process - > m_pgid ) ;
pid_t new_sid = get_sid_from_pgid ( new_pgid ) ;
if ( current_sid ! = new_sid ) {
// Can't move a process between sessions.
return - EPERM ;
}
// FIXME: There are more EPERM conditions to check for here..
process - > m_pgid = new_pgid ;
return 0 ;
}
2018-11-02 12:14:25 +00:00
2018-11-16 12:11:21 +00:00
int Process : : sys $ ioctl ( int fd , unsigned request , unsigned arg )
2018-11-02 12:14:25 +00:00
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
2018-11-02 12:14:25 +00:00
return - EBADF ;
2019-04-28 13:02:55 +00:00
if ( ! descriptor - > is_file ( ) )
2018-11-02 12:14:25 +00:00
return - ENOTTY ;
2019-04-29 11:58:40 +00:00
return descriptor - > file ( ) - > ioctl ( * descriptor , request , arg ) ;
2018-11-02 12:14:25 +00:00
}
2018-11-05 18:01:22 +00:00
int Process : : sys $ getdtablesize ( )
{
return m_max_open_file_descriptors ;
}
int Process : : sys $ dup ( int old_fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( old_fd ) ;
if ( ! descriptor )
2018-11-05 18:01:22 +00:00
return - EBADF ;
2019-04-06 12:54:32 +00:00
int new_fd = alloc_fd ( 0 ) ;
if ( new_fd < 0 )
return new_fd ;
2019-03-06 21:14:31 +00:00
m_fds [ new_fd ] . set ( * descriptor ) ;
2018-11-05 18:01:22 +00:00
return new_fd ;
}
int Process : : sys $ dup2 ( int old_fd , int new_fd )
{
2018-11-07 10:37:54 +00:00
auto * descriptor = file_descriptor ( old_fd ) ;
if ( ! descriptor )
2018-11-05 18:01:22 +00:00
return - EBADF ;
2019-04-06 12:54:32 +00:00
if ( new_fd < 0 | | new_fd > = m_max_open_file_descriptors )
return - EINVAL ;
2019-03-06 21:14:31 +00:00
m_fds [ new_fd ] . set ( * descriptor ) ;
2018-11-05 18:01:22 +00:00
return new_fd ;
}
2018-11-06 09:46:40 +00:00
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigprocmask ( int how , const sigset_t * set , sigset_t * old_set )
2018-11-10 22:29:07 +00:00
{
2018-11-11 14:36:40 +00:00
if ( old_set ) {
2019-02-21 20:33:52 +00:00
if ( ! validate_write_typed ( old_set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-03-23 21:03:17 +00:00
* old_set = current - > m_signal_mask ;
2018-11-11 14:36:40 +00:00
}
if ( set ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-11 14:36:40 +00:00
switch ( how ) {
case SIG_BLOCK :
2019-03-23 21:03:17 +00:00
current - > m_signal_mask & = ~ ( * set ) ;
2018-11-11 14:36:40 +00:00
break ;
case SIG_UNBLOCK :
2019-03-23 21:03:17 +00:00
current - > m_signal_mask | = * set ;
2018-11-11 14:36:40 +00:00
break ;
case SIG_SETMASK :
2019-03-23 21:03:17 +00:00
current - > m_signal_mask = * set ;
2018-11-11 14:36:40 +00:00
break ;
default :
return - EINVAL ;
}
2018-11-10 22:29:07 +00:00
}
return 0 ;
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigpending ( sigset_t * set )
2018-11-10 22:29:07 +00:00
{
2019-02-21 20:33:52 +00:00
if ( ! validate_write_typed ( set ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-03-23 21:03:17 +00:00
* set = current - > m_pending_signals ;
2018-11-10 22:29:07 +00:00
return 0 ;
}
2019-01-23 05:53:01 +00:00
int Process : : sys $ sigaction ( int signum , const sigaction * act , sigaction * old_act )
2018-11-06 09:46:40 +00:00
{
2018-12-24 21:22:19 +00:00
if ( signum < 1 | | signum > = 32 | | signum = = SIGKILL | | signum = = SIGSTOP )
2018-11-06 09:46:40 +00:00
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read_typed ( act ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2019-02-07 10:24:09 +00:00
InterruptDisabler disabler ; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily?
2019-03-23 21:03:17 +00:00
auto & action = current - > m_signal_action_data [ signum ] ;
2018-11-07 09:48:44 +00:00
if ( old_act ) {
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( old_act ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 09:48:44 +00:00
old_act - > sa_flags = action . flags ;
old_act - > sa_sigaction = ( decltype ( old_act - > sa_sigaction ) ) action . handler_or_sigaction . get ( ) ;
}
2018-11-06 09:46:40 +00:00
action . flags = act - > sa_flags ;
action . handler_or_sigaction = LinearAddress ( ( dword ) act - > sa_sigaction ) ;
return 0 ;
}
2018-11-07 00:38:51 +00:00
2019-02-25 21:06:55 +00:00
int Process : : sys $ getgroups ( ssize_t count , gid_t * gids )
2018-11-07 00:38:51 +00:00
{
if ( count < 0 )
return - EINVAL ;
if ( ! count )
return m_gids . size ( ) ;
2018-11-09 09:03:21 +00:00
if ( count ! = ( int ) m_gids . size ( ) )
2018-11-07 00:38:51 +00:00
return - EINVAL ;
2018-11-16 15:23:39 +00:00
if ( ! validate_write_typed ( gids , m_gids . size ( ) ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 00:38:51 +00:00
size_t i = 0 ;
for ( auto gid : m_gids )
gids [ i + + ] = gid ;
return 0 ;
}
2019-02-25 21:06:55 +00:00
int Process : : sys $ setgroups ( ssize_t count , const gid_t * gids )
2018-11-07 00:38:51 +00:00
{
2019-02-25 21:06:55 +00:00
if ( count < 0 )
return - EINVAL ;
2019-02-21 22:35:07 +00:00
if ( ! is_superuser ( ) )
2018-11-07 00:38:51 +00:00
return - EPERM ;
2018-11-16 15:23:39 +00:00
if ( ! validate_read ( gids , count ) )
2018-11-16 15:10:59 +00:00
return - EFAULT ;
2018-11-07 00:38:51 +00:00
m_gids . clear ( ) ;
m_gids . set ( m_gid ) ;
2019-02-25 21:06:55 +00:00
for ( int i = 0 ; i < count ; + + i )
2018-11-07 00:38:51 +00:00
m_gids . set ( gids [ i ] ) ;
return 0 ;
}
2018-11-18 13:57:41 +00:00
int Process : : sys $ mkdir ( const char * pathname , mode_t mode )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-02-01 14:24:42 +00:00
size_t pathname_length = strlen ( pathname ) ;
if ( pathname_length = = 0 )
return - EINVAL ;
if ( pathname_length > = 255 )
2018-11-18 13:57:41 +00:00
return - ENAMETOOLONG ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . mkdir ( StringView ( pathname , pathname_length ) , mode & ~ umask ( ) , cwd_inode ( ) ) ;
2018-11-18 13:57:41 +00:00
}
2018-12-03 00:12:26 +00:00
2019-01-23 05:53:01 +00:00
clock_t Process : : sys $ times ( tms * times )
2018-12-03 00:12:26 +00:00
{
if ( ! validate_write_typed ( times ) )
return - EFAULT ;
times - > tms_utime = m_ticks_in_user ;
times - > tms_stime = m_ticks_in_kernel ;
times - > tms_cutime = m_ticks_in_user_for_dead_children ;
times - > tms_cstime = m_ticks_in_kernel_for_dead_children ;
2019-05-17 18:19:29 +00:00
return g_uptime & 0x7fffffff ;
2018-12-03 00:12:26 +00:00
}
2019-01-09 01:29:11 +00:00
2019-01-15 22:12:20 +00:00
int Process : : sys $ select ( const Syscall : : SC_select_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
if ( params - > writefds & & ! validate_read_typed ( params - > writefds ) )
return - EFAULT ;
if ( params - > readfds & & ! validate_read_typed ( params - > readfds ) )
return - EFAULT ;
if ( params - > exceptfds & & ! validate_read_typed ( params - > exceptfds ) )
return - EFAULT ;
if ( params - > timeout & & ! validate_read_typed ( params - > timeout ) )
return - EFAULT ;
int nfds = params - > nfds ;
fd_set * writefds = params - > writefds ;
fd_set * readfds = params - > readfds ;
fd_set * exceptfds = params - > exceptfds ;
auto * timeout = params - > timeout ;
// FIXME: Implement exceptfds support.
2019-02-26 23:02:01 +00:00
( void ) exceptfds ;
2019-01-15 22:12:20 +00:00
2019-05-18 16:55:56 +00:00
if ( timeout & & ( timeout - > tv_sec | | timeout - > tv_usec ) ) {
2019-05-18 00:00:01 +00:00
struct timeval now ;
kgettimeofday ( now ) ;
AK : : timeval_add ( & now , timeout , & current - > m_select_timeout ) ;
2019-03-23 21:03:17 +00:00
current - > m_select_has_timeout = true ;
2019-02-01 02:50:06 +00:00
} else {
2019-03-23 21:03:17 +00:00
current - > m_select_has_timeout = false ;
2019-02-01 02:50:06 +00:00
}
2019-01-15 22:12:20 +00:00
if ( nfds < 0 )
return - EINVAL ;
// FIXME: Return -EINTR if a signal is caught.
// FIXME: Return -EINVAL if timeout is invalid.
2019-01-30 18:01:31 +00:00
auto transfer_fds = [ this , nfds ] ( fd_set * set , auto & vector ) - > int {
2019-05-18 00:00:54 +00:00
vector . clear_with_capacity ( ) ;
2019-01-15 22:12:20 +00:00
if ( ! set )
2019-01-30 18:01:31 +00:00
return 0 ;
2019-01-15 22:12:20 +00:00
auto bitmap = Bitmap : : wrap ( ( byte * ) set , FD_SETSIZE ) ;
for ( int i = 0 ; i < nfds ; + + i ) {
2019-01-30 18:01:31 +00:00
if ( bitmap . get ( i ) ) {
if ( ! file_descriptor ( i ) )
return - EBADF ;
2019-01-15 22:12:20 +00:00
vector . append ( i ) ;
2019-01-30 18:01:31 +00:00
}
2019-01-15 22:12:20 +00:00
}
2019-01-30 18:01:31 +00:00
return 0 ;
2019-01-15 22:12:20 +00:00
} ;
2019-01-30 18:01:31 +00:00
int error = 0 ;
2019-03-23 21:03:17 +00:00
error = transfer_fds ( writefds , current - > m_select_write_fds ) ;
2019-01-30 18:01:31 +00:00
if ( error )
return error ;
2019-03-23 21:03:17 +00:00
error = transfer_fds ( readfds , current - > m_select_read_fds ) ;
2019-01-30 18:01:31 +00:00
if ( error )
return error ;
2019-05-18 01:09:37 +00:00
error = transfer_fds ( exceptfds , current - > m_select_exceptional_fds ) ;
2019-02-26 23:02:01 +00:00
if ( error )
return error ;
2019-01-15 22:12:20 +00:00
2019-05-19 08:24:28 +00:00
# if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
2019-03-23 21:03:17 +00:00
dbgprintf ( " %s<%u> selecting on (read:%u, write:%u), timeout=%p \n " , name ( ) . characters ( ) , pid ( ) , current - > m_select_read_fds . size ( ) , current - > m_select_write_fds . size ( ) , timeout ) ;
2019-01-16 16:20:58 +00:00
# endif
2019-05-18 16:55:56 +00:00
if ( ! timeout | | current - > m_select_has_timeout )
2019-03-23 21:03:17 +00:00
current - > block ( Thread : : State : : BlockedSelect ) ;
2019-01-15 22:12:20 +00:00
int markedfds = 0 ;
if ( readfds ) {
memset ( readfds , 0 , sizeof ( fd_set ) ) ;
auto bitmap = Bitmap : : wrap ( ( byte * ) readfds , FD_SETSIZE ) ;
2019-03-23 21:03:17 +00:00
for ( int fd : current - > m_select_read_fds ) {
2019-01-23 07:03:31 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
continue ;
2019-04-29 11:58:40 +00:00
if ( descriptor - > can_read ( ) ) {
2019-01-15 22:12:20 +00:00
bitmap . set ( fd , true ) ;
+ + markedfds ;
}
}
}
if ( writefds ) {
memset ( writefds , 0 , sizeof ( fd_set ) ) ;
auto bitmap = Bitmap : : wrap ( ( byte * ) writefds , FD_SETSIZE ) ;
2019-03-23 21:03:17 +00:00
for ( int fd : current - > m_select_write_fds ) {
2019-01-23 07:03:31 +00:00
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
continue ;
2019-04-29 11:58:40 +00:00
if ( descriptor - > can_write ( ) ) {
2019-01-15 22:12:20 +00:00
bitmap . set ( fd , true ) ;
+ + markedfds ;
}
}
}
2019-02-26 23:02:01 +00:00
// FIXME: Check for exceptional conditions.
2019-01-15 22:12:20 +00:00
return markedfds ;
}
2019-01-16 16:20:58 +00:00
2019-01-23 06:27:41 +00:00
int Process : : sys $ poll ( pollfd * fds , int nfds , int timeout )
{
if ( ! validate_read_typed ( fds ) )
return - EFAULT ;
2019-01-23 07:03:31 +00:00
2019-03-23 21:03:17 +00:00
current - > m_select_write_fds . clear_with_capacity ( ) ;
current - > m_select_read_fds . clear_with_capacity ( ) ;
2019-01-23 07:03:31 +00:00
for ( int i = 0 ; i < nfds ; + + i ) {
if ( fds [ i ] . events & POLLIN )
2019-03-23 21:03:17 +00:00
current - > m_select_read_fds . append ( fds [ i ] . fd ) ;
2019-01-23 07:03:31 +00:00
if ( fds [ i ] . events & POLLOUT )
2019-03-23 21:03:17 +00:00
current - > m_select_write_fds . append ( fds [ i ] . fd ) ;
2019-01-23 07:03:31 +00:00
}
2019-05-18 01:59:48 +00:00
if ( timeout > = 0 ) {
// poll is in ms, we want s/us.
struct timeval tvtimeout ;
tvtimeout . tv_sec = 0 ;
while ( timeout > = 1000 ) {
tvtimeout . tv_sec + = 1 ;
timeout - = 1000 ;
}
tvtimeout . tv_usec = timeout * 1000 ;
struct timeval now ;
kgettimeofday ( now ) ;
AK : : timeval_add ( & now , & tvtimeout , & current - > m_select_timeout ) ;
current - > m_select_has_timeout = true ;
} else {
current - > m_select_has_timeout = false ;
}
2019-05-19 08:24:28 +00:00
# if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
dbgprintf ( " %s<%u> polling on (read:%u, write:%u), timeout=%d \n " , name ( ) . characters ( ) , pid ( ) , current - > m_select_read_fds . size ( ) , current - > m_select_write_fds . size ( ) , timeout ) ;
# endif
2019-05-18 01:59:48 +00:00
if ( current - > m_select_has_timeout | | timeout < 0 ) {
2019-03-23 21:03:17 +00:00
current - > block ( Thread : : State : : BlockedSelect ) ;
2019-05-18 01:59:48 +00:00
}
2019-01-23 07:03:31 +00:00
int fds_with_revents = 0 ;
for ( int i = 0 ; i < nfds ; + + i ) {
auto * descriptor = file_descriptor ( fds [ i ] . fd ) ;
if ( ! descriptor ) {
fds [ i ] . revents = POLLNVAL ;
continue ;
}
fds [ i ] . revents = 0 ;
2019-04-29 11:58:40 +00:00
if ( fds [ i ] . events & POLLIN & & descriptor - > can_read ( ) )
2019-01-23 07:03:31 +00:00
fds [ i ] . revents | = POLLIN ;
2019-04-29 11:58:40 +00:00
if ( fds [ i ] . events & POLLOUT & & descriptor - > can_write ( ) )
2019-01-23 07:03:31 +00:00
fds [ i ] . revents | = POLLOUT ;
if ( fds [ i ] . revents )
+ + fds_with_revents ;
}
return fds_with_revents ;
2019-01-23 06:27:41 +00:00
}
2019-02-21 15:19:07 +00:00
Inode & Process : : cwd_inode ( )
2019-01-16 16:20:58 +00:00
{
// FIXME: This is retarded factoring.
if ( ! m_cwd )
m_cwd = VFS : : the ( ) . root_inode ( ) ;
2019-02-21 15:19:07 +00:00
return * m_cwd ;
2019-01-16 16:20:58 +00:00
}
2019-01-22 06:03:44 +00:00
2019-02-21 12:26:40 +00:00
int Process : : sys $ link ( const char * old_path , const char * new_path )
{
if ( ! validate_read_str ( old_path ) )
return - EFAULT ;
if ( ! validate_read_str ( new_path ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . link ( StringView ( old_path ) , StringView ( new_path ) , cwd_inode ( ) ) ;
2019-02-21 12:26:40 +00:00
}
2019-01-22 06:03:44 +00:00
int Process : : sys $ unlink ( const char * pathname )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . unlink ( StringView ( pathname ) , cwd_inode ( ) ) ;
2019-01-22 06:03:44 +00:00
}
2019-01-25 01:09:29 +00:00
2019-03-02 00:50:34 +00:00
int Process : : sys $ symlink ( const char * target , const char * linkpath )
{
if ( ! validate_read_str ( target ) )
return - EFAULT ;
if ( ! validate_read_str ( linkpath ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . symlink ( StringView ( target ) , StringView ( linkpath ) , cwd_inode ( ) ) ;
2019-03-02 00:50:34 +00:00
}
2019-01-28 03:16:01 +00:00
int Process : : sys $ rmdir ( const char * pathname )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . rmdir ( StringView ( pathname ) , cwd_inode ( ) ) ;
2019-01-28 03:16:01 +00:00
}
2019-01-25 01:09:29 +00:00
int Process : : sys $ read_tsc ( dword * lsw , dword * msw )
{
if ( ! validate_write_typed ( lsw ) )
return - EFAULT ;
if ( ! validate_write_typed ( msw ) )
return - EFAULT ;
read_tsc ( * lsw , * msw ) ;
return 0 ;
}
2019-01-29 03:55:08 +00:00
int Process : : sys $ chmod ( const char * pathname , mode_t mode )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . chmod ( StringView ( pathname ) , mode , cwd_inode ( ) ) ;
2019-01-29 03:55:08 +00:00
}
2019-01-30 17:26:19 +00:00
2019-03-01 09:39:19 +00:00
int Process : : sys $ fchmod ( int fd , mode_t mode )
{
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
return descriptor - > fchmod ( mode ) ;
}
2019-02-27 11:32:53 +00:00
int Process : : sys $ chown ( const char * pathname , uid_t uid , gid_t gid )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . chown ( StringView ( pathname ) , uid , gid , cwd_inode ( ) ) ;
2019-02-27 11:32:53 +00:00
}
2019-02-06 17:45:21 +00:00
void Process : : finalize ( )
2019-01-30 17:26:19 +00:00
{
2019-02-06 17:45:21 +00:00
ASSERT ( current = = g_finalizer ) ;
2019-03-23 21:03:17 +00:00
dbgprintf ( " Finalizing Process %s(%u) \n " , m_name . characters ( ) , m_pid ) ;
2019-02-06 16:28:14 +00:00
2019-01-30 17:26:19 +00:00
m_fds . clear ( ) ;
2019-02-04 09:21:15 +00:00
m_tty = nullptr ;
2019-02-16 11:13:43 +00:00
disown_all_shared_buffers ( ) ;
2019-02-06 17:45:21 +00:00
{
InterruptDisabler disabler ;
if ( auto * parent_process = Process : : from_pid ( m_ppid ) ) {
2019-03-23 21:03:17 +00:00
// FIXME(Thread): What should we do here? Should we look at all threads' signal actions?
if ( parent_process - > main_thread ( ) . m_signal_action_data [ SIGCHLD ] . flags & SA_NOCLDWAIT ) {
2019-03-01 14:47:07 +00:00
// NOTE: If the parent doesn't care about this process, let it go.
m_ppid = 0 ;
} else {
parent_process - > send_signal ( SIGCHLD , this ) ;
}
2019-02-06 17:45:21 +00:00
}
2019-02-04 12:30:03 +00:00
}
2019-03-24 00:20:35 +00:00
m_dead = true ;
2019-01-30 17:26:19 +00:00
}
2019-02-03 17:53:18 +00:00
2019-02-06 17:45:21 +00:00
void Process : : die ( )
{
2019-04-22 16:44:45 +00:00
if ( m_tracer )
m_tracer - > set_dead ( ) ;
2019-03-23 21:03:17 +00:00
{
InterruptDisabler disabler ;
for_each_thread ( [ ] ( Thread & thread ) {
if ( thread . state ( ) ! = Thread : : State : : Dead )
thread . set_state ( Thread : : State : : Dying ) ;
return IterationDecision : : Continue ;
} ) ;
}
2019-02-06 17:45:21 +00:00
if ( ! Scheduler : : is_active ( ) )
Scheduler : : pick_next_and_switch_now ( ) ;
}
2019-02-03 17:53:18 +00:00
size_t Process : : amount_virtual ( ) const
{
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > size ( ) ;
}
return amount ;
}
size_t Process : : amount_resident ( ) const
{
// FIXME: This will double count if multiple regions use the same physical page.
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > amount_resident ( ) ;
}
return amount ;
}
size_t Process : : amount_shared ( ) const
{
// FIXME: This will double count if multiple regions use the same physical page.
// FIXME: It doesn't work at the moment, since it relies on PhysicalPage retain counts,
// and each PhysicalPage is only retained by its VMObject. This needs to be refactored
// so that every Region contributes +1 retain to each of its PhysicalPages.
size_t amount = 0 ;
for ( auto & region : m_regions ) {
amount + = region - > amount_shared ( ) ;
}
return amount ;
}
2019-02-06 17:45:21 +00:00
2019-02-14 13:17:38 +00:00
int Process : : sys $ socket ( int domain , int type , int protocol )
{
2019-04-06 12:54:32 +00:00
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
2019-03-06 21:14:31 +00:00
auto result = Socket : : create ( domain , type , protocol ) ;
if ( result . is_error ( ) )
return result . error ( ) ;
auto descriptor = FileDescriptor : : create ( * result . value ( ) ) ;
2019-02-14 14:17:30 +00:00
unsigned flags = 0 ;
if ( type & SOCK_CLOEXEC )
2019-02-17 09:41:37 +00:00
flags | = FD_CLOEXEC ;
2019-02-14 14:17:30 +00:00
if ( type & SOCK_NONBLOCK )
descriptor - > set_blocking ( false ) ;
m_fds [ fd ] . set ( move ( descriptor ) , flags ) ;
2019-02-14 13:17:38 +00:00
return fd ;
}
2019-02-14 13:38:30 +00:00
int Process : : sys $ bind ( int sockfd , const sockaddr * address , socklen_t address_length )
2019-02-14 13:17:38 +00:00
{
2019-02-14 13:38:30 +00:00
if ( ! validate_read ( address , address_length ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
2019-03-06 21:14:31 +00:00
return socket . bind ( address , address_length ) ;
2019-02-14 13:17:38 +00:00
}
int Process : : sys $ listen ( int sockfd , int backlog )
{
2019-02-14 14:17:30 +00:00
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
2019-03-06 21:14:31 +00:00
auto result = socket . listen ( backlog ) ;
if ( result . is_error ( ) )
return result ;
2019-02-17 08:40:52 +00:00
descriptor - > set_socket_role ( SocketRole : : Listener ) ;
2019-02-14 14:17:30 +00:00
return 0 ;
2019-02-14 13:17:38 +00:00
}
2019-02-15 10:43:43 +00:00
int Process : : sys $ accept ( int accepting_socket_fd , sockaddr * address , socklen_t * address_size )
2019-02-14 13:17:38 +00:00
{
2019-02-14 14:17:30 +00:00
if ( ! validate_write_typed ( address_size ) )
return - EFAULT ;
if ( ! validate_write ( address , * address_size ) )
return - EFAULT ;
2019-04-06 12:54:32 +00:00
int accepted_socket_fd = alloc_fd ( ) ;
if ( accepted_socket_fd < 0 )
return accepted_socket_fd ;
2019-02-15 10:43:43 +00:00
auto * accepting_socket_descriptor = file_descriptor ( accepting_socket_fd ) ;
if ( ! accepting_socket_descriptor )
2019-02-14 14:17:30 +00:00
return - EBADF ;
2019-02-15 10:43:43 +00:00
if ( ! accepting_socket_descriptor - > is_socket ( ) )
2019-02-14 14:17:30 +00:00
return - ENOTSOCK ;
2019-02-15 10:43:43 +00:00
auto & socket = * accepting_socket_descriptor - > socket ( ) ;
2019-02-14 14:17:30 +00:00
if ( ! socket . can_accept ( ) ) {
2019-02-15 10:43:43 +00:00
ASSERT ( ! accepting_socket_descriptor - > is_blocking ( ) ) ;
2019-02-14 14:17:30 +00:00
return - EAGAIN ;
}
2019-02-15 10:43:43 +00:00
auto accepted_socket = socket . accept ( ) ;
ASSERT ( accepted_socket ) ;
bool success = accepted_socket - > get_address ( address , address_size ) ;
2019-02-14 14:40:04 +00:00
ASSERT ( success ) ;
2019-02-15 10:43:43 +00:00
auto accepted_socket_descriptor = FileDescriptor : : create ( move ( accepted_socket ) , SocketRole : : Accepted ) ;
// NOTE: The accepted socket inherits fd flags from the accepting socket.
// I'm not sure if this matches other systems but it makes sense to me.
accepted_socket_descriptor - > set_blocking ( accepting_socket_descriptor - > is_blocking ( ) ) ;
m_fds [ accepted_socket_fd ] . set ( move ( accepted_socket_descriptor ) , m_fds [ accepting_socket_fd ] . flags ) ;
return accepted_socket_fd ;
2019-02-14 13:17:38 +00:00
}
2019-02-14 14:55:19 +00:00
int Process : : sys $ connect ( int sockfd , const sockaddr * address , socklen_t address_size )
2019-02-14 13:17:38 +00:00
{
2019-02-14 14:55:19 +00:00
if ( ! validate_read ( address , address_size ) )
return - EFAULT ;
2019-04-06 12:54:32 +00:00
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
2019-02-14 14:55:19 +00:00
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
2019-03-20 01:38:36 +00:00
if ( descriptor - > socket_role ( ) = = SocketRole : : Connected )
return - EISCONN ;
2019-02-14 14:55:19 +00:00
auto & socket = * descriptor - > socket ( ) ;
2019-03-20 01:33:51 +00:00
descriptor - > set_socket_role ( SocketRole : : Connecting ) ;
2019-05-03 18:15:54 +00:00
auto result = socket . connect ( * descriptor , address , address_size , descriptor - > is_blocking ( ) ? ShouldBlock : : Yes : ShouldBlock : : No ) ;
2019-03-20 01:38:36 +00:00
if ( result . is_error ( ) ) {
descriptor - > set_socket_role ( SocketRole : : None ) ;
2019-03-06 21:14:31 +00:00
return result ;
2019-03-20 01:38:36 +00:00
}
2019-02-14 16:18:35 +00:00
descriptor - > set_socket_role ( SocketRole : : Connected ) ;
return 0 ;
}
2019-03-12 14:51:42 +00:00
ssize_t Process : : sys $ sendto ( const Syscall : : SC_sendto_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
int sockfd = params - > sockfd ;
const void * data = params - > data ;
size_t data_length = params - > data_length ;
int flags = params - > flags ;
auto * addr = ( const sockaddr * ) params - > addr ;
auto addr_length = ( socklen_t ) params - > addr_length ;
if ( ! validate_read ( data , data_length ) )
return - EFAULT ;
2019-03-13 22:14:30 +00:00
if ( addr & & ! validate_read ( addr , addr_length ) )
2019-03-12 14:51:42 +00:00
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
kprintf ( " sendto %p (%u), flags=%u, addr: %p (%u) \n " , data , data_length , flags , addr , addr_length ) ;
2019-05-03 18:15:54 +00:00
return socket . sendto ( * descriptor , data , data_length , flags , addr , addr_length ) ;
2019-03-12 14:51:42 +00:00
}
2019-03-12 16:27:07 +00:00
ssize_t Process : : sys $ recvfrom ( const Syscall : : SC_recvfrom_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
int sockfd = params - > sockfd ;
void * buffer = params - > buffer ;
size_t buffer_length = params - > buffer_length ;
int flags = params - > flags ;
2019-03-13 13:47:21 +00:00
auto * addr = ( sockaddr * ) params - > addr ;
auto * addr_length = ( socklen_t * ) params - > addr_length ;
2019-03-12 16:27:07 +00:00
if ( ! validate_write ( buffer , buffer_length ) )
return - EFAULT ;
2019-03-13 22:14:30 +00:00
if ( addr_length ) {
2019-05-04 01:27:50 +00:00
if ( ! validate_write_typed ( addr_length ) )
2019-03-13 22:14:30 +00:00
return - EFAULT ;
2019-05-04 01:27:50 +00:00
if ( ! validate_write ( addr , * addr_length ) )
2019-03-13 22:14:30 +00:00
return - EFAULT ;
} else if ( addr ) {
return - EINVAL ;
}
2019-03-12 16:27:07 +00:00
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
2019-05-20 01:44:45 +00:00
bool original_blocking = descriptor - > is_blocking ( ) ;
if ( flags & MSG_DONTWAIT )
descriptor - > set_blocking ( false ) ;
auto nrecv = socket . recvfrom ( * descriptor , buffer , buffer_length , flags , addr , addr_length ) ;
if ( flags & MSG_DONTWAIT )
descriptor - > set_blocking ( original_blocking ) ;
return nrecv ;
2019-03-12 16:27:07 +00:00
}
2019-05-19 17:55:27 +00:00
int Process : : sys $ getsockname ( int sockfd , sockaddr * addr , socklen_t * addrlen )
{
if ( ! validate_read_typed ( addrlen ) )
return - EFAULT ;
if ( * addrlen < = 0 )
return - EINVAL ;
if ( ! validate_write ( addr , * addrlen ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
if ( ! socket . get_address ( addr , addrlen ) )
return - EINVAL ; // FIXME: Should this be another error? I'm not sure.
return 0 ;
}
2019-03-13 12:13:23 +00:00
int Process : : sys $ getsockopt ( const Syscall : : SC_getsockopt_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
int sockfd = params - > sockfd ;
int level = params - > level ;
int option = params - > option ;
auto * value = params - > value ;
auto * value_size = ( socklen_t * ) params - > value_size ;
if ( ! validate_write_typed ( value_size ) )
return - EFAULT ;
if ( ! validate_write ( value , * value_size ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
return socket . getsockopt ( level , option , value , value_size ) ;
}
int Process : : sys $ setsockopt ( const Syscall : : SC_setsockopt_params * params )
{
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
int sockfd = params - > sockfd ;
int level = params - > level ;
int option = params - > option ;
auto * value = params - > value ;
auto value_size = ( socklen_t ) params - > value_size ;
if ( ! validate_read ( value , value_size ) )
return - EFAULT ;
auto * descriptor = file_descriptor ( sockfd ) ;
if ( ! descriptor )
return - EBADF ;
if ( ! descriptor - > is_socket ( ) )
return - ENOTSOCK ;
auto & socket = * descriptor - > socket ( ) ;
return socket . setsockopt ( level , option , value , value_size ) ;
}
2019-02-16 11:13:43 +00:00
struct SharedBuffer {
2019-03-08 11:22:55 +00:00
SharedBuffer ( pid_t pid1 , pid_t pid2 , int size )
2019-02-16 11:13:43 +00:00
: m_pid1 ( pid1 )
, m_pid2 ( pid2 )
, m_vmo ( VMObject : : create_anonymous ( size ) )
{
ASSERT ( pid1 ! = pid2 ) ;
}
void * retain ( Process & process )
{
if ( m_pid1 = = process . pid ( ) ) {
+ + m_pid1_retain_count ;
2019-02-16 23:13:47 +00:00
if ( ! m_pid1_region ) {
2019-03-08 11:22:55 +00:00
m_pid1_region = process . allocate_region_with_vmo ( LinearAddress ( ) , size ( ) , m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , m_pid1_writable ) ;
2019-02-16 23:13:47 +00:00
m_pid1_region - > set_shared ( true ) ;
}
2019-02-16 11:13:43 +00:00
return m_pid1_region - > laddr ( ) . as_ptr ( ) ;
} else if ( m_pid2 = = process . pid ( ) ) {
+ + m_pid2_retain_count ;
2019-02-16 23:13:47 +00:00
if ( ! m_pid2_region ) {
2019-03-08 11:22:55 +00:00
m_pid2_region = process . allocate_region_with_vmo ( LinearAddress ( ) , size ( ) , m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , m_pid2_writable ) ;
2019-02-16 23:13:47 +00:00
m_pid2_region - > set_shared ( true ) ;
}
2019-02-16 11:13:43 +00:00
return m_pid2_region - > laddr ( ) . as_ptr ( ) ;
}
return nullptr ;
}
void release ( Process & process )
{
if ( m_pid1 = = process . pid ( ) ) {
ASSERT ( m_pid1_retain_count ) ;
- - m_pid1_retain_count ;
if ( ! m_pid1_retain_count ) {
if ( m_pid1_region )
process . deallocate_region ( * m_pid1_region ) ;
m_pid1_region = nullptr ;
}
destroy_if_unused ( ) ;
} else if ( m_pid2 = = process . pid ( ) ) {
ASSERT ( m_pid2_retain_count ) ;
- - m_pid2_retain_count ;
if ( ! m_pid2_retain_count ) {
if ( m_pid2_region )
process . deallocate_region ( * m_pid2_region ) ;
m_pid2_region = nullptr ;
}
destroy_if_unused ( ) ;
}
}
void disown ( pid_t pid )
{
if ( m_pid1 = = pid ) {
m_pid1 = 0 ;
m_pid1_retain_count = 0 ;
destroy_if_unused ( ) ;
} else if ( m_pid2 = = pid ) {
m_pid2 = 0 ;
m_pid2_retain_count = 0 ;
destroy_if_unused ( ) ;
}
}
pid_t pid1 ( ) const { return m_pid1 ; }
pid_t pid2 ( ) const { return m_pid2 ; }
unsigned pid1_retain_count ( ) const { return m_pid1_retain_count ; }
unsigned pid2_retain_count ( ) const { return m_pid2_retain_count ; }
size_t size ( ) const { return m_vmo - > size ( ) ; }
void destroy_if_unused ( ) ;
2019-03-08 11:22:55 +00:00
void seal ( )
{
m_pid1_writable = false ;
m_pid2_writable = false ;
if ( m_pid1_region ) {
m_pid1_region - > set_writable ( false ) ;
MM . remap_region ( * m_pid1_region - > page_directory ( ) , * m_pid1_region ) ;
}
if ( m_pid2_region ) {
m_pid2_region - > set_writable ( false ) ;
MM . remap_region ( * m_pid2_region - > page_directory ( ) , * m_pid2_region ) ;
}
}
2019-02-16 11:13:43 +00:00
int m_shared_buffer_id { - 1 } ;
pid_t m_pid1 ;
pid_t m_pid2 ;
unsigned m_pid1_retain_count { 1 } ;
unsigned m_pid2_retain_count { 0 } ;
Region * m_pid1_region { nullptr } ;
Region * m_pid2_region { nullptr } ;
2019-03-08 11:22:55 +00:00
bool m_pid1_writable { false } ;
bool m_pid2_writable { false } ;
2019-02-25 15:04:08 +00:00
Retained < VMObject > m_vmo ;
2019-02-16 11:13:43 +00:00
} ;
static int s_next_shared_buffer_id ;
Lockable < HashMap < int , OwnPtr < SharedBuffer > > > & shared_buffers ( )
{
static Lockable < HashMap < int , OwnPtr < SharedBuffer > > > * map ;
if ( ! map )
map = new Lockable < HashMap < int , OwnPtr < SharedBuffer > > > ;
return * map ;
}
void SharedBuffer : : destroy_if_unused ( )
{
if ( ! m_pid1_retain_count & & ! m_pid2_retain_count ) {
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-03-08 11:22:55 +00:00
kprintf ( " Destroying unused SharedBuffer{%p} id: %d (pid1: %d, pid2: %d) \n " , this , m_shared_buffer_id , m_pid1 , m_pid2 ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-05-17 13:59:57 +00:00
auto count_before = shared_buffers ( ) . resource ( ) . size ( ) ;
2019-02-16 11:13:43 +00:00
shared_buffers ( ) . resource ( ) . remove ( m_shared_buffer_id ) ;
2019-02-20 14:34:55 +00:00
ASSERT ( count_before ! = shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 11:13:43 +00:00
}
}
void Process : : disown_all_shared_buffers ( )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
2019-04-20 12:02:19 +00:00
Vector < SharedBuffer * , 32 > buffers_to_disown ;
2019-02-20 20:31:52 +00:00
for ( auto & it : shared_buffers ( ) . resource ( ) )
buffers_to_disown . append ( it . value . ptr ( ) ) ;
for ( auto * shared_buffer : buffers_to_disown )
shared_buffer - > disown ( m_pid ) ;
2019-02-16 11:13:43 +00:00
}
2019-03-08 11:22:55 +00:00
int Process : : sys $ create_shared_buffer ( pid_t peer_pid , int size , void * * buffer )
2019-02-16 11:13:43 +00:00
{
2019-03-08 11:22:55 +00:00
if ( ! size | | size < 0 )
2019-02-20 20:31:52 +00:00
return - EINVAL ;
size = PAGE_ROUND_UP ( size ) ;
2019-02-16 11:13:43 +00:00
if ( ! peer_pid | | peer_pid < 0 | | peer_pid = = m_pid )
return - EINVAL ;
if ( ! validate_write_typed ( buffer ) )
return - EFAULT ;
{
InterruptDisabler disabler ;
auto * peer = Process : : from_pid ( peer_pid ) ;
if ( ! peer )
return - ESRCH ;
}
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
int shared_buffer_id = + + s_next_shared_buffer_id ;
auto shared_buffer = make < SharedBuffer > ( m_pid , peer_pid , size ) ;
2019-02-20 14:34:55 +00:00
shared_buffer - > m_shared_buffer_id = shared_buffer_id ;
2019-02-20 20:31:52 +00:00
ASSERT ( shared_buffer - > size ( ) > = size ) ;
2019-02-16 11:13:43 +00:00
shared_buffer - > m_pid1_region = allocate_region_with_vmo ( LinearAddress ( ) , shared_buffer - > size ( ) , shared_buffer - > m_vmo . copy_ref ( ) , 0 , " SharedBuffer " , true , true ) ;
2019-02-16 23:13:47 +00:00
shared_buffer - > m_pid1_region - > set_shared ( true ) ;
2019-02-16 11:13:43 +00:00
* buffer = shared_buffer - > m_pid1_region - > laddr ( ) . as_ptr ( ) ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-03-08 11:22:55 +00:00
kprintf ( " %s(%u): Created shared buffer %d (%u bytes, vmo is %u) for sharing with %d \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , size , shared_buffer - > size ( ) , peer_pid ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-16 11:13:43 +00:00
shared_buffers ( ) . resource ( ) . set ( shared_buffer_id , move ( shared_buffer ) ) ;
return shared_buffer_id ;
}
int Process : : sys $ release_shared_buffer ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-03-08 11:22:55 +00:00
kprintf ( " %s(%u): Releasing shared buffer %d, buffer count: %u \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-16 11:13:43 +00:00
shared_buffer . release ( * this ) ;
return 0 ;
}
void * Process : : sys $ get_shared_buffer ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return ( void * ) - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
if ( shared_buffer . pid1 ( ) ! = m_pid & & shared_buffer . pid2 ( ) ! = m_pid )
return ( void * ) - EINVAL ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-03-08 11:22:55 +00:00
kprintf ( " %s(%u): Retaining shared buffer %d, buffer count: %u \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , shared_buffers ( ) . resource ( ) . size ( ) ) ;
2019-02-16 23:13:47 +00:00
# endif
2019-02-16 11:13:43 +00:00
return shared_buffer . retain ( * this ) ;
}
2019-03-05 09:34:08 +00:00
2019-03-08 11:22:55 +00:00
int Process : : sys $ seal_shared_buffer ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
if ( shared_buffer . pid1 ( ) ! = m_pid & & shared_buffer . pid2 ( ) ! = m_pid )
return - EINVAL ;
# ifdef SHARED_BUFFER_DEBUG
kprintf ( " %s(%u): Sealing shared buffer %d \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id ) ;
# endif
shared_buffer . seal ( ) ;
return 0 ;
}
int Process : : sys $ get_shared_buffer_size ( int shared_buffer_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( shared_buffer_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
if ( shared_buffer . pid1 ( ) ! = m_pid & & shared_buffer . pid2 ( ) ! = m_pid )
return - EINVAL ;
# ifdef SHARED_BUFFER_DEBUG
kprintf ( " %s(%u): Get shared buffer %d size: %u \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , shared_buffers ( ) . resource ( ) . size ( ) ) ;
# endif
return shared_buffer . size ( ) ;
}
2019-03-05 09:34:08 +00:00
const char * to_string ( Process : : Priority priority )
{
switch ( priority ) {
2019-04-20 13:58:45 +00:00
case Process : : IdlePriority : return " Idle " ;
2019-03-05 09:34:08 +00:00
case Process : : LowPriority : return " Low " ;
case Process : : NormalPriority : return " Normal " ;
case Process : : HighPriority : return " High " ;
}
kprintf ( " to_string(Process::Priority): Invalid priority: %u \n " , priority ) ;
ASSERT_NOT_REACHED ( ) ;
return nullptr ;
}
2019-03-23 21:03:17 +00:00
void Process : : terminate_due_to_signal ( byte signal )
{
ASSERT_INTERRUPTS_DISABLED ( ) ;
ASSERT ( signal < 32 ) ;
dbgprintf ( " terminate_due_to_signal %s(%u) <- %u \n " , name ( ) . characters ( ) , pid ( ) , signal ) ;
m_termination_status = 0 ;
m_termination_signal = signal ;
die ( ) ;
}
void Process : : send_signal ( byte signal , Process * sender )
{
// FIXME(Thread): Find the appropriate thread to deliver the signal to.
main_thread ( ) . send_signal ( signal , sender ) ;
}
int Process : : thread_count ( ) const
{
int count = 0 ;
for_each_thread ( [ & count ] ( auto & ) {
+ + count ;
return IterationDecision : : Continue ;
} ) ;
return count ;
}
2019-03-23 21:59:08 +00:00
int Process : : sys $ create_thread ( int ( * entry ) ( void * ) , void * argument )
{
if ( ! validate_read ( ( const void * ) entry , sizeof ( void * ) ) )
return - EFAULT ;
auto * thread = new Thread ( * this ) ;
auto & tss = thread - > tss ( ) ;
tss . eip = ( dword ) entry ;
tss . eflags = 0x0202 ;
tss . cr3 = page_directory ( ) . cr3 ( ) ;
thread - > make_userspace_stack_for_secondary_thread ( argument ) ;
thread - > set_state ( Thread : : State : : Runnable ) ;
return 0 ;
}
2019-03-25 12:03:49 +00:00
2019-04-29 13:17:20 +00:00
void Process : : sys $ exit_thread ( int code )
{
2019-04-29 13:56:25 +00:00
cli ( ) ;
2019-04-29 13:17:20 +00:00
if ( & current - > process ( ) . main_thread ( ) = = current ) {
sys $ exit ( code ) ;
return ;
}
current - > set_state ( Thread : : State : : Dying ) ;
2019-04-29 13:56:25 +00:00
big_lock ( ) . unlock_if_locked ( ) ;
2019-04-29 13:17:20 +00:00
Scheduler : : pick_next_and_switch_now ( ) ;
ASSERT_NOT_REACHED ( ) ;
}
2019-03-25 12:03:49 +00:00
int Process : : sys $ gettid ( )
{
return current - > tid ( ) ;
}
int Process : : sys $ donate ( int tid )
{
if ( tid < 0 )
return - EINVAL ;
InterruptDisabler disabler ;
Thread * beneficiary = nullptr ;
for_each_thread ( [ & ] ( Thread & thread ) {
if ( thread . tid ( ) = = tid ) {
beneficiary = & thread ;
return IterationDecision : : Abort ;
}
return IterationDecision : : Continue ;
} ) ;
if ( ! beneficiary )
return - ENOTHREAD ;
Scheduler : : donate_to ( beneficiary , " sys$donate " ) ;
return 0 ;
}
2019-04-07 21:35:26 +00:00
int Process : : sys $ rename ( const char * oldpath , const char * newpath )
{
if ( ! validate_read_str ( oldpath ) )
return - EFAULT ;
if ( ! validate_read_str ( newpath ) )
return - EFAULT ;
2019-04-15 12:57:27 +00:00
return VFS : : the ( ) . rename ( StringView ( oldpath ) , StringView ( newpath ) , cwd_inode ( ) ) ;
2019-04-07 21:35:26 +00:00
}
2019-04-08 21:44:12 +00:00
int Process : : sys $ shm_open ( const char * name , int flags , mode_t mode )
{
if ( ! validate_read_str ( name ) )
return - EFAULT ;
2019-04-09 00:37:05 +00:00
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
auto shm_or_error = SharedMemory : : open ( String ( name ) , flags , mode ) ;
if ( shm_or_error . is_error ( ) )
return shm_or_error . error ( ) ;
auto descriptor = FileDescriptor : : create ( shm_or_error . value ( ) . ptr ( ) ) ;
m_fds [ fd ] . set ( move ( descriptor ) , FD_CLOEXEC ) ;
return fd ;
2019-04-08 21:44:12 +00:00
}
int Process : : sys $ shm_unlink ( const char * name )
{
if ( ! validate_read_str ( name ) )
return - EFAULT ;
2019-04-09 00:37:05 +00:00
return SharedMemory : : unlink ( String ( name ) ) ;
2019-04-08 21:44:12 +00:00
}
2019-04-08 23:10:00 +00:00
int Process : : sys $ ftruncate ( int fd , off_t length )
{
auto * descriptor = file_descriptor ( fd ) ;
if ( ! descriptor )
return - EBADF ;
// FIXME: Check that fd is writable, otherwise EINVAL.
if ( ! descriptor - > is_file ( ) & & ! descriptor - > is_shared_memory ( ) )
return - EINVAL ;
return descriptor - > truncate ( length ) ;
}
2019-04-22 16:44:45 +00:00
int Process : : sys $ systrace ( pid_t pid )
{
InterruptDisabler disabler ;
auto * peer = Process : : from_pid ( pid ) ;
if ( ! peer )
return - ESRCH ;
if ( peer - > uid ( ) ! = m_euid )
return - EACCES ;
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
auto descriptor = FileDescriptor : : create ( peer - > ensure_tracer ( ) ) ;
m_fds [ fd ] . set ( move ( descriptor ) , 0 ) ;
return fd ;
}
ProcessTracer & Process : : ensure_tracer ( )
{
if ( ! m_tracer )
m_tracer = ProcessTracer : : create ( m_pid ) ;
return * m_tracer ;
}
2019-04-29 02:55:54 +00:00
void Process : : FileDescriptorAndFlags : : clear ( )
{
descriptor = nullptr ;
flags = 0 ;
}
void Process : : FileDescriptorAndFlags : : set ( Retained < FileDescriptor > & & d , dword f )
{
descriptor = move ( d ) ;
flags = f ;
}
2019-05-03 20:59:58 +00:00
int Process : : sys $ mknod ( const char * pathname , mode_t mode , dev_t dev )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
return VFS : : the ( ) . mknod ( StringView ( pathname ) , mode , dev , cwd_inode ( ) ) ;
}