2019-05-23 14:42:13 +00:00
# include <AK/ELF/ELFLoader.h>
2019-06-07 09:43:58 +00:00
# include <AK/ELF/exec_elf.h>
2019-08-25 16:17:05 +00:00
# include <AK/FileSystemPath.h>
2019-06-07 09:43:58 +00:00
# include <AK/StdLibExtras.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-06-07 09:43:58 +00:00
# include <AK/Types.h>
2019-06-07 18:02:01 +00:00
# include <Kernel/Arch/i386/CPU.h>
2019-07-09 12:23:12 +00:00
# include <Kernel/Arch/i386/PIT.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/Devices/NullDevice.h>
2019-10-13 14:41:55 +00:00
# include <Kernel/Devices/RandomDevice.h>
2019-05-30 16:58:59 +00:00
# include <Kernel/FileSystem/Custody.h>
2019-08-15 16:13:56 +00:00
# include <Kernel/FileSystem/DevPtsFS.h>
2019-08-29 18:57:02 +00:00
# include <Kernel/FileSystem/Ext2FileSystem.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/FileSystem/FIFO.h>
# include <Kernel/FileSystem/FileDescription.h>
2019-07-22 18:01:11 +00:00
# include <Kernel/FileSystem/InodeWatcher.h>
2019-08-29 18:57:02 +00:00
# include <Kernel/FileSystem/ProcFS.h>
2019-07-09 12:50:01 +00:00
# include <Kernel/FileSystem/SharedMemory.h>
2019-08-29 18:57:02 +00:00
# include <Kernel/FileSystem/TmpFS.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/FileSystem/VirtualFileSystem.h>
2019-07-19 07:58:12 +00:00
# include <Kernel/IO.h>
2019-08-07 19:52:43 +00:00
# include <Kernel/KBufferBuilder.h>
2019-06-07 17:29:34 +00:00
# include <Kernel/KSyms.h>
2019-06-02 07:50:18 +00:00
# include <Kernel/Multiboot.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/Net/Socket.h>
2019-06-07 17:29:34 +00:00
# include <Kernel/Process.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/ProcessTracer.h>
2019-06-07 17:29:34 +00:00
# include <Kernel/RTC.h>
# include <Kernel/Scheduler.h>
2019-07-16 13:03:39 +00:00
# include <Kernel/SharedBuffer.h>
2019-07-19 07:58:12 +00:00
# include <Kernel/StdLib.h>
2019-06-07 17:29:34 +00:00
# include <Kernel/Syscall.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/TTY/MasterPTY.h>
2019-08-07 16:06:17 +00:00
# include <Kernel/VM/InodeVMObject.h>
2019-09-16 07:01:44 +00:00
# include <Kernel/Heap/kmalloc.h>
2019-06-07 09:43:58 +00:00
# include <LibC/errno_numbers.h>
# include <LibC/signal_numbers.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-07-15 18:38:41 +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
2019-07-19 15:01:16 +00:00
static void create_signal_trampolines ( ) ;
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 ;
2019-07-19 15:01:16 +00:00
VirtualAddress g_return_to_ring3_from_signal_trampoline ;
VirtualAddress g_return_to_ring0_from_signal_trampoline ;
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 ;
2019-07-19 15:01:16 +00:00
create_signal_trampolines ( ) ;
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-08-08 12:40:13 +00:00
for ( auto & process : * g_processes )
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 ( ) ) ;
2019-08-08 12:40:13 +00:00
for ( auto & process : * g_processes )
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-06-07 10:56:50 +00:00
Range Process : : allocate_range ( VirtualAddress vaddr , size_t size )
2018-10-18 11:05:00 +00:00
{
2019-06-07 10:56:50 +00:00
vaddr . mask ( PAGE_MASK ) ;
2019-01-12 23:27:25 +00:00
size = PAGE_ROUND_UP ( size ) ;
2019-06-07 10:56:50 +00:00
if ( vaddr . is_null ( ) )
2019-05-20 02:46:29 +00:00
return page_directory ( ) . range_allocator ( ) . allocate_anywhere ( size ) ;
2019-06-07 10:56:50 +00:00
return page_directory ( ) . range_allocator ( ) . allocate_specific ( vaddr , size ) ;
2019-05-17 02:39:22 +00:00
}
2019-05-17 01:40:15 +00:00
2019-05-30 14:14:37 +00:00
static unsigned prot_to_region_access_flags ( int prot )
{
unsigned access = 0 ;
if ( prot & PROT_READ )
access | = Region : : Access : : Read ;
if ( prot & PROT_WRITE )
access | = Region : : Access : : Write ;
if ( prot & PROT_EXEC )
access | = Region : : Access : : Execute ;
return access ;
}
2019-09-27 18:17:41 +00:00
Region & Process : : allocate_split_region ( const Region & source_region , const Range & range , size_t offset_in_vmo )
2019-08-29 18:57:02 +00:00
{
2019-09-27 18:17:41 +00:00
m_regions . append ( Region : : create_user_accessible ( range , source_region . vmobject ( ) , offset_in_vmo , source_region . name ( ) , source_region . access ( ) ) ) ;
2019-08-29 18:57:02 +00:00
return m_regions . last ( ) ;
}
2019-06-07 18:58:12 +00:00
Region * Process : : allocate_region ( VirtualAddress vaddr , size_t size , const String & name , int prot , bool commit )
2019-05-17 02:39:22 +00:00
{
2019-06-07 10:56:50 +00:00
auto range = allocate_range ( vaddr , size ) ;
2019-05-17 02:39:22 +00:00
if ( ! range . is_valid ( ) )
return nullptr ;
2019-07-19 14:09:34 +00:00
m_regions . append ( Region : : create_user_accessible ( range , name , prot_to_region_access_flags ( prot ) ) ) ;
2019-06-27 11:34:28 +00:00
MM . map_region ( * this , m_regions . last ( ) ) ;
2019-01-22 04:01:00 +00:00
if ( commit )
2019-06-27 11:34:28 +00:00
m_regions . last ( ) . commit ( ) ;
return & m_regions . last ( ) ;
2018-10-18 11:05:00 +00:00
}
2019-07-19 14:09:34 +00:00
Region * Process : : allocate_file_backed_region ( VirtualAddress vaddr , size_t size , NonnullRefPtr < Inode > inode , const String & name , int prot )
2018-11-08 11:59:16 +00:00
{
2019-06-07 10:56:50 +00:00
auto range = allocate_range ( vaddr , size ) ;
2019-05-17 02:39:22 +00:00
if ( ! range . is_valid ( ) )
return nullptr ;
2019-07-19 14:09:34 +00:00
m_regions . append ( Region : : create_user_accessible ( range , inode , name , prot_to_region_access_flags ( prot ) ) ) ;
2019-06-27 11:34:28 +00:00
MM . map_region ( * this , m_regions . last ( ) ) ;
return & m_regions . last ( ) ;
2018-11-08 11:59:16 +00:00
}
2019-07-11 13:38:47 +00:00
Region * Process : : allocate_region_with_vmo ( VirtualAddress vaddr , size_t size , NonnullRefPtr < VMObject > vmo , size_t offset_in_vmo , const String & name , int prot )
2018-11-08 20:20:09 +00:00
{
2019-06-07 10:56:50 +00:00
auto range = allocate_range ( vaddr , size ) ;
2019-05-17 02:39:22 +00:00
if ( ! range . is_valid ( ) )
return nullptr ;
2018-11-08 20:20:09 +00:00
offset_in_vmo & = PAGE_MASK ;
2019-07-19 14:09:34 +00:00
m_regions . append ( Region : : create_user_accessible ( range , move ( vmo ) , offset_in_vmo , name , prot_to_region_access_flags ( prot ) ) ) ;
2019-06-27 11:34:28 +00:00
MM . map_region ( * this , m_regions . last ( ) ) ;
return & m_regions . last ( ) ;
2018-11-08 20:20:09 +00:00
}
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-06-27 11:34:28 +00:00
if ( & m_regions [ i ] = = & region ) {
2018-10-24 07:48:24 +00:00
m_regions . remove ( i ) ;
return true ;
}
}
return false ;
}
2019-08-29 18:57:02 +00:00
Region * Process : : region_from_range ( const Range & range )
{
size_t size = PAGE_ROUND_UP ( range . size ( ) ) ;
for ( auto & region : m_regions ) {
if ( region . vaddr ( ) = = range . base ( ) & & region . size ( ) = = size )
return & region ;
}
return nullptr ;
}
Region * Process : : region_containing ( const Range & range )
2018-10-24 07:48:24 +00:00
{
for ( auto & region : m_regions ) {
2019-08-29 18:57:02 +00:00
if ( region . contains ( range ) )
2019-06-27 11:34:28 +00:00
return & region ;
2018-10-24 07:48:24 +00:00
}
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-08-29 18:57:02 +00:00
auto * region = region_from_range ( { VirtualAddress ( ( u32 ) 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-07-03 19:17:35 +00:00
if ( ( u32 ) addr & ~ PAGE_MASK )
2018-11-08 11:59:16 +00:00
return ( void * ) - EINVAL ;
2019-10-01 17:31:55 +00:00
if ( ( flags & MAP_SHARED ) & & ( flags & MAP_PRIVATE ) )
return ( void * ) - EINVAL ;
2018-11-08 11:59:16 +00:00
if ( flags & MAP_ANONYMOUS ) {
2019-09-22 17:47:00 +00:00
auto * region = allocate_region ( VirtualAddress ( ( u32 ) addr ) , size , name ? name : " mmap " , prot , 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-06-07 10:56:50 +00:00
return region - > vaddr ( ) . as_ptr ( ) ;
2018-11-08 11:59:16 +00:00
}
if ( offset & ~ PAGE_MASK )
return ( void * ) - EINVAL ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-11-08 11:59:16 +00:00
return ( void * ) - EBADF ;
2019-07-03 19:17:35 +00:00
auto region_or_error = description - > mmap ( * this , VirtualAddress ( ( u32 ) addr ) , offset , size , prot ) ;
2019-04-28 13:02:55 +00:00
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-06-07 10:56:50 +00:00
return region - > vaddr ( ) . 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-08-29 18:57:02 +00:00
Range range_to_unmap { VirtualAddress ( ( u32 ) addr ) , size } ;
if ( auto * whole_region = region_from_range ( range_to_unmap ) ) {
bool success = deallocate_region ( * whole_region ) ;
ASSERT ( success ) ;
return 0 ;
}
if ( auto * old_region = region_containing ( range_to_unmap ) ) {
Range old_region_range = old_region - > range ( ) ;
auto remaining_ranges_after_unmap = old_region_range . carve ( range_to_unmap ) ;
ASSERT ( ! remaining_ranges_after_unmap . is_empty ( ) ) ;
auto make_replacement_region = [ & ] ( const Range & new_range ) - > Region & {
ASSERT ( new_range . base ( ) > = old_region_range . base ( ) ) ;
2019-09-27 18:17:41 +00:00
ASSERT ( new_range . end ( ) < = old_region_range . end ( ) ) ;
2019-10-01 09:38:59 +00:00
size_t new_range_offset_in_vmobject = old_region - > offset_in_vmobject ( ) + ( new_range . base ( ) . get ( ) - old_region_range . base ( ) . get ( ) ) ;
return allocate_split_region ( * old_region , new_range , new_range_offset_in_vmobject ) ;
2019-08-29 18:57:02 +00:00
} ;
Vector < Region * , 2 > new_regions ;
for ( auto & new_range : remaining_ranges_after_unmap ) {
new_regions . unchecked_append ( & make_replacement_region ( new_range ) ) ;
}
2019-09-27 18:17:41 +00:00
// We manually unmap the old region here, specifying that we *don't* want the VM deallocated.
MM . unmap_region ( * old_region , false ) ;
2019-08-29 18:57:02 +00:00
deallocate_region ( * old_region ) ;
2019-09-27 18:17:41 +00:00
// Instead we give back the unwanted VM manually.
page_directory ( ) . range_allocator ( ) . deallocate ( range_to_unmap ) ;
// And finally we map the new region(s).
2019-08-29 18:57:02 +00:00
for ( auto * new_region : new_regions ) {
MM . map_region ( * this , * new_region ) ;
}
return 0 ;
}
// FIXME: We should also support munmap() across multiple regions. (#175)
return - EINVAL ;
2018-10-24 07:48:24 +00:00
}
2019-08-12 17:33:24 +00:00
int Process : : sys $ mprotect ( void * addr , size_t size , int prot )
{
2019-08-29 18:57:02 +00:00
auto * region = region_from_range ( { VirtualAddress ( ( u32 ) addr ) , size } ) ;
2019-08-12 17:33:24 +00:00
if ( ! region )
return - EINVAL ;
region - > set_writable ( prot & PROT_WRITE ) ;
MM . remap_region ( page_directory ( ) , * region ) ;
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-07-11 13:38:47 +00:00
auto * child = new Process ( String ( m_name ) , m_uid , m_gid , m_pid , m_ring , m_cwd , m_executable , m_tty , this ) ;
2018-11-10 22:29:07 +00:00
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-09-27 11:57:35 +00:00
dbg ( ) < < " fork: cloning Region{ " < < & region < < " } ' " < < region . name ( ) < < " ' @ " < < region . vaddr ( ) ;
2018-11-02 19:41:58 +00:00
# endif
2019-09-27 12:19:07 +00:00
child - > m_regions . append ( region . clone ( ) ) ;
2019-06-27 11:34:28 +00:00
MM . map_region ( * child , child - > m_regions . last ( ) ) ;
2019-09-07 13:50:44 +00:00
if ( & region = = m_master_tls_region )
2019-09-27 12:19:07 +00:00
child - > m_master_tls_region = & 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 " ) ;
2019-06-07 09:43:58 +00:00
for_each_thread ( [ ] ( Thread & thread ) {
2019-04-23 20:17:01 +00:00
dbgprintf ( " Thread{%p}: TID=%d, PID=%d \n " , & thread , thread . tid ( ) , thread . pid ( ) ) ;
return IterationDecision : : Continue ;
} ) ;
ASSERT ( thread_count ( ) = = 1 ) ;
ASSERT_NOT_REACHED ( ) ;
}
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-06-02 10:19:21 +00:00
auto result = VFS : : the ( ) . open ( path , 0 , 0 , current_directory ( ) ) ;
2019-03-06 21:14:31 +00:00
if ( result . is_error ( ) )
return result . error ( ) ;
2019-06-13 20:03:04 +00:00
auto description = result . value ( ) ;
auto metadata = description - > metadata ( ) ;
2018-11-03 00:49:40 +00:00
2019-05-31 05:02:43 +00:00
if ( ! metadata . may_execute ( m_euid , m_gids ) )
2018-11-03 00:49:40 +00:00
return - EACCES ;
2019-05-31 05:02:43 +00:00
if ( ! metadata . size )
2018-11-08 20:20:09 +00:00
return - ENOTIMPL ;
2019-07-03 19:17:35 +00:00
u32 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-08-06 09:19:16 +00:00
m_page_directory = PageDirectory : : create_for_userspace ( * this ) ;
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-08-07 16:06:17 +00:00
ASSERT ( description - > inode ( ) ) ;
auto vmo = InodeVMObject : : create_with_inode ( * description - > inode ( ) ) ;
2019-09-27 12:19:07 +00:00
auto * region = allocate_region_with_vmo ( VirtualAddress ( ) , metadata . size , vmo , 0 , description - > absolute_path ( ) , PROT_READ ) ;
2019-05-17 02:39:22 +00:00
ASSERT ( region ) ;
2019-01-22 04:01:00 +00:00
2019-09-27 12:19:07 +00:00
// NOTE: We yank this out of 'm_regions' since we're about to manipulate the vector
// and we don't want it getting lost.
auto executable_region = m_regions . take_last ( ) ;
Region * master_tls_region { nullptr } ;
2019-09-07 13:50:44 +00:00
size_t master_tls_size = 0 ;
size_t master_tls_alignment = 0 ;
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-09-27 12:19:07 +00:00
m_regions . append ( move ( executable_region ) ) ;
2019-06-07 10:56:50 +00:00
loader = make < ELFLoader > ( region - > vaddr ( ) . as_ptr ( ) ) ;
loader - > map_section_hook = [ & ] ( VirtualAddress vaddr , size_t size , size_t alignment , size_t offset_in_image , bool is_readable , bool is_writable , bool is_executable , 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-05-30 14:14:37 +00:00
int prot = 0 ;
if ( is_readable )
prot | = PROT_READ ;
if ( is_writable )
prot | = PROT_WRITE ;
if ( is_executable )
prot | = PROT_EXEC ;
2019-07-11 13:38:47 +00:00
( void ) allocate_region_with_vmo ( vaddr , size , vmo , offset_in_image , String ( name ) , prot ) ;
2019-06-07 10:56:50 +00:00
return vaddr . as_ptr ( ) ;
2018-11-08 20:20:09 +00:00
} ;
2019-06-07 10:56:50 +00:00
loader - > alloc_section_hook = [ & ] ( VirtualAddress vaddr , 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 ) ;
2019-05-30 14:14:37 +00:00
int prot = 0 ;
if ( is_readable )
prot | = PROT_READ ;
if ( is_writable )
prot | = PROT_WRITE ;
2019-06-07 10:56:50 +00:00
( void ) allocate_region ( vaddr , size , String ( name ) , prot ) ;
return vaddr . as_ptr ( ) ;
2018-11-03 00:49:40 +00:00
} ;
2019-09-07 13:50:44 +00:00
loader - > tls_section_hook = [ & ] ( size_t size , size_t alignment ) {
ASSERT ( size ) ;
master_tls_region = allocate_region ( { } , size , String ( ) , PROT_READ | PROT_WRITE ) ;
master_tls_size = size ;
master_tls_alignment = alignment ;
return master_tls_region - > vaddr ( ) . as_ptr ( ) ;
} ;
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 ) ;
2019-09-27 12:19:07 +00:00
executable_region = m_regions . take_first ( ) ;
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-31 05:02:43 +00:00
// NOTE: At this point, we've committed to the new executable.
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-06-13 20:03:04 +00:00
m_executable = description - > custody ( ) ;
2019-05-31 05:02:43 +00:00
2019-09-07 13:50:44 +00:00
// Copy of the master TLS region that we will clone for new threads
2019-09-27 12:19:07 +00:00
m_master_tls_region = master_tls_region ;
2019-09-07 13:50:44 +00:00
2019-05-31 05:02:43 +00:00
if ( metadata . is_setuid ( ) )
m_euid = metadata . uid ;
if ( metadata . is_setgid ( ) )
m_egid = metadata . gid ;
2019-05-16 15:18:25 +00:00
2019-03-23 21:03:17 +00:00
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 ] ;
2019-06-13 20:03:04 +00:00
if ( daf . description & & daf . flags & FD_CLOEXEC ) {
daf . description - > close ( ) ;
2019-06-07 09:43:58 +00:00
daf = { } ;
2018-11-13 00:36:31 +00:00
}
}
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!!!!!!!!!
2019-07-03 19:17:35 +00:00
u32 old_esp0 = main_thread ( ) . m_tss . esp0 ;
2019-03-23 21:03:17 +00:00
2019-09-07 13:50:44 +00:00
m_master_tls_size = master_tls_size ;
m_master_tls_alignment = master_tls_alignment ;
main_thread ( ) . make_thread_specific_region ( { } ) ;
2019-03-23 21:03:17 +00:00
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 ;
2019-09-07 13:50:44 +00:00
main_thread ( ) . m_tss . gs = thread_specific_selector ( ) | 3 ;
2019-03-23 21:03:17 +00:00
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
# 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 ) ;
2019-07-17 12:15:13 +00:00
big_lock ( ) . unlock_if_locked ( ) ;
2018-11-09 16:59:14 +00:00
return 0 ;
}
2019-09-15 09:47:21 +00:00
KResultOr < String > Process : : find_shebang_interpreter_for_executable ( const String & executable_path )
{
// FIXME: It's a bit sad that we'll open the executable twice (in case there's no shebang)
// Maybe we can find a way to plumb this opened FileDescription to the rest of the
// exec implementation..
auto result = VFS : : the ( ) . open ( executable_path , 0 , 0 , current_directory ( ) ) ;
if ( result . is_error ( ) )
return result . error ( ) ;
auto description = result . value ( ) ;
auto metadata = description - > metadata ( ) ;
if ( ! metadata . may_execute ( m_euid , m_gids ) )
return KResult ( - EACCES ) ;
if ( metadata . size < 3 )
return KResult ( - ENOEXEC ) ;
char first_page [ PAGE_SIZE ] ;
int nread = description - > read ( ( u8 * ) & first_page , sizeof ( first_page ) ) ;
int interpreter_length = 0 ;
if ( nread > 2 & & first_page [ 0 ] = = ' # ' & & first_page [ 1 ] = = ' ! ' ) {
for ( int i = 2 ; i < nread ; + + i ) {
if ( first_page [ i ] = = ' \n ' ) {
interpreter_length = i - 2 ;
break ;
}
}
if ( interpreter_length > 0 )
return String ( & first_page [ 2 ] , interpreter_length ) ;
}
return KResult ( - ENOEXEC ) ;
}
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
{
2019-09-15 09:47:21 +00:00
auto result = find_shebang_interpreter_for_executable ( path ) ;
if ( ! result . is_error ( ) )
return exec ( result . value ( ) , { result . value ( ) , path } , move ( 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-06-21 16:37:47 +00:00
RefPtr < Custody > 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-07-11 13:38:47 +00:00
cwd = parent - > m_cwd ;
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-05-30 16:58:59 +00:00
cwd = VFS : : the ( ) . root_custody ( ) ;
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-07-03 19:17:35 +00:00
process - > main_thread ( ) . tss ( ) . eip = ( u32 ) 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-07-11 13:38:47 +00:00
Process : : Process ( String & & name , uid_t uid , gid_t gid , pid_t ppid , RingLevel ring , RefPtr < Custody > cwd , RefPtr < Custody > 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 )
2019-05-30 18:23:50 +00:00
, m_executable ( move ( executable ) )
, m_cwd ( move ( cwd ) )
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-08-06 09:19:16 +00:00
m_page_directory = PageDirectory : : create_for_userspace ( * this , fork_parent ? & fork_parent - > page_directory ( ) . range_allocator ( ) : nullptr ) ;
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 ) {
2019-06-13 20:03:04 +00:00
if ( ! fork_parent - > m_fds [ i ] . description )
2018-11-02 19:41:58 +00:00
continue ;
# ifdef FORK_DEBUG
2019-06-13 20:03:04 +00:00
dbgprintf ( " fork: cloning fd %u... (%p) istty? %u \n " , i , fork_parent - > m_fds [ i ] . description . ptr ( ) , fork_parent - > m_fds [ i ] . description - > is_tty ( ) ) ;
2018-11-02 19:41:58 +00:00
# endif
2019-08-11 13:07:47 +00:00
m_fds [ i ] = fork_parent - > m_fds [ i ] ;
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 ;
2019-06-07 09:43:58 +00:00
for_each_thread ( [ & my_threads ] ( auto & thread ) {
2019-04-23 20:17:01 +00:00
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 ( ) ) ;
2019-08-12 17:37:28 +00:00
kprintf ( " BEGIN END SIZE ACCESS NAME \n " ) ;
2018-10-18 12:53:00 +00:00
for ( auto & region : m_regions ) {
2019-08-17 19:29:46 +00:00
kprintf ( " %08x -- %08x %08x %c%c%c %s \n " ,
2019-06-27 11:34:28 +00:00
region . vaddr ( ) . get ( ) ,
region . vaddr ( ) . offset ( region . size ( ) - 1 ) . get ( ) ,
region . size ( ) ,
2019-08-12 17:37:28 +00:00
region . is_readable ( ) ? ' R ' : ' ' ,
region . is_writable ( ) ? ' W ' : ' ' ,
region . is_executable ( ) ? ' X ' : ' ' ,
2019-06-27 11:34:28 +00:00
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-09-17 13:41:42 +00:00
void signal_trampoline_dummy ( void )
{
// The trampoline preserves the current eax, pushes the signal code and
// then calls the signal handler. We do this because, when interrupting a
// blocking syscall, that syscall may return some special error code in eax;
// This error code would likely be overwritten by the signal handler, so it's
// neccessary to preserve it here.
asm (
" .intel_syntax noprefix \n "
" asm_signal_trampoline: \n "
" push ebp \n "
" mov ebp, esp \n "
" push eax \n " // we have to store eax 'cause it might be the return value from a syscall
" sub esp, 4 \n " // align the stack to 16 bytes
" mov eax, [ebp+12] \n " // push the signal code
" push eax \n "
" call [ebp+8] \n " // call the signal handler
" add esp, 8 \n "
" mov eax, %P0 \n "
" int 0x82 \n " // sigreturn syscall
" asm_signal_trampoline_end: \n "
" .att_syntax " : : " i " ( Syscall : : SC_sigreturn ) ) ;
}
2019-09-04 13:14:54 +00:00
extern " C " void asm_signal_trampoline ( void ) ;
extern " C " void asm_signal_trampoline_end ( void ) ;
2019-07-19 15:01:16 +00:00
void create_signal_trampolines ( )
2019-03-05 11:50:55 +00:00
{
2019-07-19 15:01:16 +00:00
InterruptDisabler disabler ;
// NOTE: We leak this region.
2019-09-27 12:19:07 +00:00
auto * trampoline_region = MM . allocate_user_accessible_kernel_region ( PAGE_SIZE , " Signal trampolines " ) . leak_ptr ( ) ;
2019-07-19 15:01:16 +00:00
g_return_to_ring3_from_signal_trampoline = trampoline_region - > vaddr ( ) ;
2019-09-04 13:14:54 +00:00
u8 * trampoline = ( u8 * ) asm_signal_trampoline ;
u8 * trampoline_end = ( u8 * ) asm_signal_trampoline_end ;
size_t trampoline_size = trampoline_end - trampoline ;
2019-07-19 15:01:16 +00:00
u8 * code_ptr = ( u8 * ) trampoline_region - > vaddr ( ) . as_ptr ( ) ;
2019-09-04 13:14:54 +00:00
memcpy ( code_ptr , trampoline , trampoline_size ) ;
2019-07-19 15:01:16 +00:00
trampoline_region - > set_writable ( false ) ;
MM . remap_region ( * trampoline_region - > page_directory ( ) , * trampoline_region ) ;
2019-03-05 11:50:55 +00:00
}
2019-07-03 19:17:35 +00:00
int Process : : sys $ restore_signal_mask ( u32 mask )
2019-03-05 09:34:08 +00:00
{
2019-03-23 21:03:17 +00:00
current - > m_signal_mask = mask ;
2019-03-05 09:34:08 +00:00
return 0 ;
}
2019-09-04 13:14:54 +00:00
int Process : : sys $ sigreturn ( RegisterDump & registers )
2018-11-07 20:19:47 +00:00
{
2019-09-04 13:14:54 +00:00
//Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
u32 * stack_ptr = ( u32 * ) registers . esp_if_crossRing ;
u32 smuggled_eax = * stack_ptr ;
//pop the stored eax, ebp, return address, handler and signal code
stack_ptr + = 5 ;
current - > m_signal_mask = * stack_ptr ;
stack_ptr + + ;
2019-10-04 14:31:34 +00:00
//pop edi, esi, ebp, esp, ebx, edx, ecx and eax
memcpy ( & registers . edi , stack_ptr , 8 * sizeof ( u32 ) ) ;
stack_ptr + = 8 ;
registers . eip = * stack_ptr ;
stack_ptr + + ;
2019-09-04 13:14:54 +00:00
registers . eflags = * stack_ptr ;
stack_ptr + + ;
registers . esp_if_crossRing = registers . esp ;
return smuggled_eax ;
2018-11-06 09:46:40 +00:00
}
2019-07-03 19:17:35 +00:00
void Process : : crash ( int signal , u32 eip )
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-06-19 16:50:02 +00:00
if ( m_elf_loader & & ksyms_ready )
dbgprintf ( " \033 [31;1m%p %s \033 [0m \n " , eip , m_elf_loader - > symbolicate ( eip ) . characters ( ) ) ;
2019-05-16 17:49:48 +00:00
dump_backtrace ( ) ;
2019-05-26 00:08:51 +00:00
m_termination_signal = signal ;
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 ( ) ;
2019-08-08 12:40:13 +00:00
for ( auto & process : * g_processes ) {
if ( process . pid ( ) = = pid )
return & process ;
2018-10-16 09:01:38 +00:00
}
return nullptr ;
}
2019-06-07 07:36:51 +00:00
FileDescription * Process : : file_description ( 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 ( ) )
2019-06-13 20:03:04 +00:00
return m_fds [ fd ] . description . ptr ( ) ;
2018-11-07 10:37:54 +00:00
return nullptr ;
}
2019-06-07 07:36:51 +00:00
const FileDescription * Process : : file_description ( int fd ) const
2018-11-07 10:37:54 +00:00
{
if ( fd < 0 )
return nullptr ;
2019-02-25 21:06:55 +00:00
if ( fd < m_fds . size ( ) )
2019-06-13 20:03:04 +00:00
return m_fds [ fd ] . description . ptr ( ) ;
2018-10-16 09:01:38 +00:00
return nullptr ;
}
2019-09-28 20:00:38 +00:00
int Process : : fd_flags ( int fd ) const
{
if ( fd < 0 )
return - 1 ;
if ( fd < m_fds . size ( ) )
return m_fds [ fd ] . flags ;
return - 1 ;
}
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2019-07-03 19:17:35 +00:00
return description - > get_dir_entries ( ( u8 * ) 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
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-10-31 16:50:43 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
return description - > 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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_tty ( ) )
2018-10-30 21:03:02 +00:00
return - ENOTTY ;
2019-06-13 20:03:04 +00:00
auto tty_name = description - > tty ( ) - > tty_name ( ) ;
2019-01-31 16:31:23 +00:00
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2019-01-15 05:30:19 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
auto * master_pty = description - > master_pty ( ) ;
2019-01-15 05:30:19 +00:00
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
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
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 ) {
2019-07-03 19:17:35 +00:00
int rc = do_write ( * description , ( const u8 * ) iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
2019-05-10 01:19:25 +00:00
if ( rc < 0 ) {
if ( nwritten = = 0 )
return rc ;
return nwritten ;
}
nwritten + = rc ;
}
if ( current - > has_unmasked_pending_signals ( ) ) {
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : SemiPermanentBlocker > ( Thread : : SemiPermanentBlocker : : Reason : : Signal ) = = Thread : : BlockResult : : InterruptedBySignal ) {
if ( nwritten = = 0 )
return - EINTR ;
}
2019-05-10 01:19:25 +00:00
}
return nwritten ;
}
2019-07-03 19:17:35 +00:00
ssize_t Process : : do_write ( FileDescription & description , const u8 * data , int data_size )
2019-05-10 01:19:25 +00:00
{
2018-11-12 00:28:46 +00:00
ssize_t nwritten = 0 ;
2019-06-13 20:03:04 +00:00
if ( ! description . is_blocking ( ) ) {
if ( ! description . can_write ( ) )
2019-05-19 08:25:05 +00:00
return - EAGAIN ;
}
2019-05-10 01:19:25 +00:00
2019-06-13 20:03:04 +00:00
if ( description . should_append ( ) ) {
2019-05-25 23:18:04 +00:00
# ifdef IO_DEBUG
dbgprintf ( " seeking to end (O_APPEND) \n " ) ;
# endif
2019-06-13 20:03:04 +00:00
description . seek ( 0 , SEEK_END ) ;
2019-05-25 23:18:04 +00:00
}
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-06-13 20:03:04 +00:00
if ( ! description . 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-07-20 09:05:52 +00:00
if ( current - > block < Thread : : WriteBlocker > ( description ) = = Thread : : BlockResult : : InterruptedBySignal ) {
if ( nwritten = = 0 )
return - EINTR ;
}
2019-05-10 01:19:25 +00:00
}
2019-06-13 20:03:04 +00:00
ssize_t rc = description . 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 ( ) ) {
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : SemiPermanentBlocker > ( Thread : : SemiPermanentBlocker : : Reason : : Signal ) = = Thread : : BlockResult : : InterruptedBySignal ) {
if ( nwritten = = 0 )
return - EINTR ;
}
2019-05-10 01:19:25 +00:00
}
nwritten + = rc ;
2018-11-12 00:28:46 +00:00
}
2019-05-10 01:19:25 +00:00
return nwritten ;
}
2019-07-03 19:17:35 +00:00
ssize_t Process : : sys $ write ( int fd , const u8 * data , ssize_t size )
2019-05-10 01:19:25 +00:00
{
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
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2019-05-10 01:19:25 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
auto nwritten = do_write ( * description , data , size ) ;
2019-03-23 21:03:17 +00:00
if ( current - > has_unmasked_pending_signals ( ) ) {
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : SemiPermanentBlocker > ( Thread : : SemiPermanentBlocker : : Reason : : Signal ) = = Thread : : BlockResult : : InterruptedBySignal ) {
if ( nwritten = = 0 )
return - EINTR ;
}
2018-11-10 01:43:33 +00:00
}
2018-10-30 14:33:37 +00:00
return nwritten ;
}
2019-07-03 19:17:35 +00:00
ssize_t Process : : sys $ read ( int fd , u8 * 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
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-10-30 14:33:37 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( description - > is_blocking ( ) ) {
if ( ! description - > can_read ( ) ) {
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : ReadBlocker > ( * description ) = = Thread : : BlockResult : : InterruptedBySignal )
2018-11-07 20:19:47 +00:00
return - EINTR ;
2018-10-25 11:07:59 +00:00
}
}
2019-06-13 20:03:04 +00:00
return description - > 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
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-10-30 21:03:02 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
int rc = description - > close ( ) ;
2019-06-07 09:43:58 +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-05-30 18:23:50 +00:00
return VFS : : the ( ) . utime ( StringView ( pathname ) , current_directory ( ) , 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-05-30 18:23:50 +00:00
return VFS : : the ( ) . access ( StringView ( pathname ) , mode , current_directory ( ) ) ;
2018-11-10 23:20:53 +00:00
}
2019-07-03 19:17:35 +00:00
int Process : : sys $ fcntl ( int fd , int cmd , u32 arg )
2018-11-11 09:38:33 +00:00
{
2019-06-07 09:43:58 +00:00
( void ) cmd ;
( void ) arg ;
2018-11-11 14:36:40 +00:00
dbgprintf ( " sys$fcntl: fd=%d, cmd=%d, arg=%u \n " , fd , cmd , arg ) ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-11-11 09:38:33 +00:00
return - EBADF ;
2019-06-07 07:36:51 +00:00
// NOTE: The FD flags are not shared between FileDescription objects.
2018-11-13 00:36:31 +00:00
// 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-06-13 20:03:04 +00:00
m_fds [ new_fd ] . set ( * description ) ;
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 :
2019-06-13 20:03:04 +00:00
return description - > file_flags ( ) ;
2018-11-11 14:36:40 +00:00
case F_SETFL :
2019-06-13 20:03:04 +00:00
description - > set_file_flags ( arg ) ;
2018-11-13 00:36:31 +00:00
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-11-10 23:20:53 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
return description - > 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-08-02 17:23:23 +00:00
auto metadata_or_error = VFS : : the ( ) . lookup_metadata ( StringView ( path ) , current_directory ( ) , O_NOFOLLOW_NOERROR ) ;
if ( metadata_or_error . is_error ( ) )
return metadata_or_error . error ( ) ;
return metadata_or_error . value ( ) . stat ( * 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-08-02 17:23:23 +00:00
auto metadata_or_error = VFS : : the ( ) . lookup_metadata ( StringView ( path ) , current_directory ( ) ) ;
if ( metadata_or_error . is_error ( ) )
return metadata_or_error . error ( ) ;
return metadata_or_error . value ( ) . stat ( * 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-05-30 18:23:50 +00:00
auto result = VFS : : the ( ) . open ( path , O_RDONLY | O_NOFOLLOW_NOERROR , 0 , current_directory ( ) ) ;
2019-03-06 21:14:31 +00:00
if ( result . is_error ( ) )
return result . error ( ) ;
2019-06-13 20:03:04 +00:00
auto description = result . value ( ) ;
2018-10-28 13:11:51 +00:00
2019-06-13 20:03:04 +00:00
if ( ! description - > metadata ( ) . is_symlink ( ) )
2018-10-28 13:11:51 +00:00
return - EINVAL ;
2019-06-13 20:03:04 +00:00
auto contents = description - > read_entire_file ( ) ;
2018-10-28 13:11:51 +00:00
if ( ! contents )
return - EIO ; // FIXME: Get a more detailed error from VFS.
2019-09-30 06:57:01 +00:00
memcpy ( buffer , contents . data ( ) , 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-05-30 18:23:50 +00:00
auto directory_or_error = VFS : : the ( ) . open_directory ( StringView ( path ) , current_directory ( ) ) ;
2019-03-01 22:54:07 +00:00
if ( directory_or_error . is_error ( ) )
return directory_or_error . error ( ) ;
2019-05-30 18:23:50 +00:00
m_cwd = * directory_or_error . value ( ) ;
2018-10-24 12:28:22 +00:00
return 0 ;
}
2019-09-11 23:18:25 +00:00
int Process : : sys $ fchdir ( int fd )
{
auto * description = file_description ( fd ) ;
if ( ! description )
return - EBADF ;
if ( ! description - > is_directory ( ) )
return - ENOTDIR ;
2019-09-13 12:35:18 +00:00
if ( ! description - > metadata ( ) . may_execute ( * this ) )
return - EACCES ;
2019-09-11 23:18:25 +00:00
m_cwd = description - > custody ( ) ;
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-05-30 18:23:50 +00:00
auto path = current_directory ( ) . absolute_path ( ) ;
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 ;
2019-06-13 20:03:04 +00:00
for ( auto & description : m_fds ) {
if ( description )
2018-11-01 12:39:28 +00:00
+ + count ;
}
return count ;
}
2019-07-08 18:01:49 +00:00
int Process : : sys $ open ( const Syscall : : SC_open_params * params )
2018-10-16 09:01:38 +00:00
{
2019-07-08 18:01:49 +00:00
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
auto * path = params - > path ;
auto path_length = params - > path_length ;
auto options = params - > options ;
auto mode = params - > mode ;
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
2019-07-08 18:01:49 +00:00
if ( ! validate_read ( path , path_length ) )
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-05-30 18:23:50 +00:00
auto result = VFS : : the ( ) . open ( path , options , mode & ~ umask ( ) , current_directory ( ) ) ;
2019-03-06 21:14:31 +00:00
if ( result . is_error ( ) )
return result . error ( ) ;
2019-06-13 20:03:04 +00:00
auto description = result . value ( ) ;
if ( options & O_DIRECTORY & & ! description - > is_directory ( ) )
2018-10-28 13:11:51 +00:00
return - ENOTDIR ; // FIXME: This should be handled by VFS::open.
2019-06-13 20:03:04 +00:00
description - > set_file_flags ( options ) ;
2019-07-03 19:17:35 +00:00
u32 fd_flags = ( options & O_CLOEXEC ) ? FD_CLOEXEC : 0 ;
2019-06-13 20:03:04 +00:00
m_fds [ fd ] . set ( move ( description ) , fd_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 ;
}
2019-08-05 12:29:05 +00:00
int Process : : sys $ pipe ( int pipefd [ 2 ] , int flags )
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-08-05 12:29:05 +00:00
// Reject flags other than O_CLOEXEC.
if ( ( flags & O_CLOEXEC ) ! = flags )
return - EINVAL ;
u32 fd_flags = ( flags & O_CLOEXEC ) ? FD_CLOEXEC : 0 ;
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-08-05 12:29:05 +00:00
m_fds [ reader_fd ] . set ( fifo - > open_direction ( FIFO : : Direction : : Reader ) , fd_flags ) ;
2018-11-12 00:28:46 +00:00
pipefd [ 0 ] = reader_fd ;
int writer_fd = alloc_fd ( ) ;
2019-08-05 12:29:05 +00:00
m_fds [ writer_fd ] . set ( fifo - > open_direction ( FIFO : : Direction : : Writer ) , fd_flags ) ;
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 ;
2019-06-07 09:43:58 +00:00
( void ) pgrp ;
2018-11-10 23:20:53 +00:00
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 )
{
2019-06-07 09:30:07 +00:00
unsigned previous_alarm_remaining = 0 ;
if ( m_alarm_deadline & & m_alarm_deadline > g_uptime ) {
previous_alarm_remaining = ( m_alarm_deadline - g_uptime ) / TICKS_PER_SECOND ;
}
if ( ! seconds ) {
m_alarm_deadline = 0 ;
return previous_alarm_remaining ;
}
m_alarm_deadline = g_uptime + seconds * TICKS_PER_SECOND ;
return previous_alarm_remaining ;
2018-11-10 23:20:53 +00:00
}
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 )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-11-05 17:16:00 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > 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 ) {
2019-08-22 19:16:49 +00:00
Process : : for_each_in_pgrp ( pgid ( ) , [ & ] ( auto & process ) {
process . send_signal ( signal , this ) ;
return IterationDecision : : Continue ;
} ) ;
return 0 ;
2018-10-16 09:01:38 +00:00
}
if ( pid = = - 1 ) {
// FIXME: Send to all processes.
ASSERT ( pid ! = - 1 ) ;
}
2019-02-28 08:44:48 +00:00
if ( pid = = m_pid ) {
2019-07-25 19:02:19 +00:00
// FIXME: If we ignore this signal anyway, we don't need to block here, right?
2019-03-23 21:03:17 +00:00
current - > send_signal ( signal , this ) ;
2019-07-20 09:05:52 +00:00
( void ) current - > block < Thread : : SemiPermanentBlocker > ( Thread : : SemiPermanentBlocker : : Reason : : Signal ) ;
2019-02-28 08:44:48 +00:00
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-07-18 15:26:11 +00:00
u64 wakeup_time = current - > sleep ( usec / 1000 ) ;
if ( wakeup_time > g_uptime ) {
u32 ticks_left_until_original_wakeup_time = 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-07-18 15:26:11 +00:00
u64 wakeup_time = current - > sleep ( seconds * TICKS_PER_SECOND ) ;
if ( wakeup_time > g_uptime ) {
u32 ticks_left_until_original_wakeup_time = 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-06-06 15:46:41 +00:00
timeval kgettimeofday ( )
2019-03-13 12:13:23 +00:00
{
2019-06-06 15:46:41 +00:00
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-06-06 15:46:41 +00:00
return tv ;
}
void kgettimeofday ( timeval & tv )
{
tv = kgettimeofday ( ) ;
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-07-19 07:51:48 +00:00
dbgprintf ( " reap: %s(%u) {%s} \n " , process . name ( ) . characters ( ) , process . pid ( ) , process . main_thread ( ) . state_string ( ) ) ;
2019-03-27 13:38:32 +00:00
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 ) ;
2019-07-14 09:35:49 +00:00
if ( ! options ) {
// FIXME: This can't be right.. can it? Figure out how this should actually work.
options = WEXITED ;
}
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 ) {
2019-07-14 09:35:49 +00:00
// FIXME: Figure out what WNOHANG should do with stopped children.
2018-11-16 23:11:08 +00:00
if ( waitee = = - 1 ) {
pid_t reaped_pid = 0 ;
InterruptDisabler disabler ;
2019-06-07 09:43:58 +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
}
2019-07-14 09:35:49 +00:00
return IterationDecision : : Continue ;
2018-11-16 23:11:08 +00:00
} ) ;
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-07-18 16:05:19 +00:00
pid_t waitee_pid = waitee ;
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : WaitBlocker > ( options , waitee_pid ) = = Thread : : BlockResult : : InterruptedBySignal )
2018-11-07 20:19:47 +00:00
return - EINTR ;
2019-07-14 09:35:49 +00:00
InterruptDisabler disabler ;
// NOTE: If waitee was -1, m_waitee_pid will have been filled in by the scheduler.
2019-07-18 16:05:19 +00:00
Process * waitee_process = Process : : from_pid ( waitee_pid ) ;
2019-09-08 11:54:48 +00:00
if ( ! waitee_process )
return - ECHILD ;
2018-11-09 00:25:31 +00:00
ASSERT ( waitee_process ) ;
2019-07-14 09:35:49 +00:00
if ( waitee_process - > is_dead ( ) ) {
exit_status = reap ( * waitee_process ) ;
} else {
ASSERT ( waitee_process - > main_thread ( ) . state ( ) = = Thread : : State : : Stopped ) ;
exit_status = 0x7f ;
}
2019-07-18 16:05:19 +00:00
return waitee_pid ;
2018-10-16 09:01:38 +00:00
}
2019-06-07 18:02:01 +00:00
enum class KernelMemoryCheckResult {
2019-02-11 05:03:30 +00:00
NotInsideKernelMemory ,
AccessGranted ,
AccessDenied
} ;
2019-06-07 10:56:50 +00:00
static KernelMemoryCheckResult check_kernel_memory_access ( VirtualAddress vaddr , bool is_write )
2019-01-27 09:17:56 +00:00
{
2019-06-02 07:50:18 +00:00
auto & sections = multiboot_info_ptr - > u . elf_sec ;
2019-05-18 01:06:34 +00:00
2019-06-02 07:50:18 +00:00
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-06-07 10:56:50 +00:00
if ( vaddr . get ( ) < segment . p_vaddr | | vaddr . get ( ) > ( segment . p_vaddr + segment . p_memsz ) )
2019-02-06 16:28:14 +00:00
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-06-07 10:56:50 +00:00
bool Process : : validate_read_from_kernel ( VirtualAddress vaddr ) const
2018-10-26 22:14:24 +00:00
{
2019-06-07 10:56:50 +00:00
if ( vaddr . is_null ( ) )
2019-04-15 21:48:31 +00:00
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-06-07 10:56:50 +00:00
auto kmc_result = check_kernel_memory_access ( vaddr , false ) ;
2019-02-11 05:03:30 +00:00
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-06-07 10:56:50 +00:00
if ( is_kmalloc_address ( vaddr . as_ptr ( ) ) )
2018-10-26 22:14:24 +00:00
return true ;
2019-06-07 10:56:50 +00:00
return validate_read ( vaddr . 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-07-03 19:17:35 +00:00
VirtualAddress first_address ( ( u32 ) address ) ;
2019-06-07 10:56:50 +00:00
VirtualAddress 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-07-03 19:17:35 +00:00
VirtualAddress first_address ( ( u32 ) address ) ;
2019-06-07 10:56:50 +00:00
VirtualAddress 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 ;
2019-06-07 09:43:58 +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 ;
2019-08-22 19:12:55 +00:00
return IterationDecision : : Break ;
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
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2018-11-02 12:14:25 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
return description - > file ( ) . ioctl ( * description , 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 )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( old_fd ) ;
if ( ! description )
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-06-13 20:03:04 +00:00
m_fds [ new_fd ] . set ( * description ) ;
2018-11-05 18:01:22 +00:00
return new_fd ;
}
int Process : : sys $ dup2 ( int old_fd , int new_fd )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( old_fd ) ;
if ( ! description )
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-06-13 20:03:04 +00:00
m_fds [ new_fd ] . set ( * description ) ;
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 ;
2019-07-03 19:17:35 +00:00
action . handler_or_sigaction = VirtualAddress ( ( u32 ) act - > sa_sigaction ) ;
2018-11-06 09:46:40 +00:00
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . mkdir ( StringView ( pathname , pathname_length ) , mode & ~ umask ( ) , current_directory ( ) ) ;
2018-11-18 13:57:41 +00:00
}
2018-12-03 00:12:26 +00:00
2019-08-25 16:17:05 +00:00
int Process : : sys $ realpath ( const char * pathname , char * buffer , size_t size )
{
if ( ! validate_read_str ( pathname ) )
return - EFAULT ;
size_t pathname_length = strlen ( pathname ) ;
if ( pathname_length = = 0 )
return - EINVAL ;
if ( pathname_length > = size )
return - ENAMETOOLONG ;
if ( ! validate_write ( buffer , size ) )
return - EFAULT ;
auto custody_or_error = VFS : : the ( ) . resolve_path ( pathname , current_directory ( ) ) ;
if ( custody_or_error . is_error ( ) )
return custody_or_error . error ( ) ;
auto & custody = custody_or_error . value ( ) ;
// FIXME: Once resolve_path is fixed to deal with .. and . , remove the use of FileSystemPath::canonical_path.
FileSystemPath canonical_path ( custody - > absolute_path ( ) ) ;
if ( ! canonical_path . is_valid ( ) ) {
2019-08-29 19:01:33 +00:00
dbg ( ) < < " FileSystemPath failed to canonicalize " < < custody - > absolute_path ( ) ;
ASSERT_NOT_REACHED ( ) ;
2019-08-25 16:17:05 +00:00
}
strncpy ( buffer , canonical_path . string ( ) . characters ( ) , size ) ;
return 0 ;
} ;
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 )
{
2019-06-06 15:46:41 +00:00
// FIXME: Return -EINTR if a signal is caught.
// FIXME: Return -EINVAL if timeout is invalid.
2019-01-15 22:12:20 +00:00
if ( ! validate_read_typed ( params ) )
return - EFAULT ;
2019-06-06 15:46:41 +00:00
if ( params - > writefds & & ! validate_write_typed ( params - > writefds ) )
2019-01-15 22:12:20 +00:00
return - EFAULT ;
2019-06-06 15:46:41 +00:00
if ( params - > readfds & & ! validate_write_typed ( params - > readfds ) )
2019-01-15 22:12:20 +00:00
return - EFAULT ;
2019-06-06 15:46:41 +00:00
if ( params - > exceptfds & & ! validate_write_typed ( params - > exceptfds ) )
2019-01-15 22:12:20 +00:00
return - EFAULT ;
if ( params - > timeout & & ! validate_read_typed ( params - > timeout ) )
return - EFAULT ;
2019-06-06 15:46:41 +00:00
if ( params - > nfds < 0 )
return - EINVAL ;
2019-01-15 22:12:20 +00:00
2019-07-18 15:39:49 +00:00
timeval timeout ;
bool select_has_timeout = false ;
2019-06-06 15:46:41 +00:00
if ( params - > timeout & & ( params - > timeout - > tv_sec | | params - > timeout - > tv_usec ) ) {
2019-07-18 15:39:49 +00:00
timeval_add ( kgettimeofday ( ) , * params - > timeout , timeout ) ;
select_has_timeout = true ;
2019-02-01 02:50:06 +00:00
}
2019-01-15 22:12:20 +00:00
2019-07-19 07:04:12 +00:00
Thread : : SelectBlocker : : FDVector rfds ;
Thread : : SelectBlocker : : FDVector wfds ;
Thread : : SelectBlocker : : FDVector efds ;
2019-07-18 15:39:49 +00:00
2019-06-07 09:43:58 +00:00
auto transfer_fds = [ & ] ( auto * fds , auto & vector ) - > int {
2019-05-18 00:00:54 +00:00
vector . clear_with_capacity ( ) ;
2019-06-06 15:46:41 +00:00
if ( ! fds )
2019-01-30 18:01:31 +00:00
return 0 ;
2019-06-06 15:46:41 +00:00
for ( int fd = 0 ; fd < params - > nfds ; + + fd ) {
if ( FD_ISSET ( fd , fds ) ) {
2019-06-07 07:36:51 +00:00
if ( ! file_description ( fd ) )
2019-01-30 18:01:31 +00:00
return - EBADF ;
2019-06-06 15:46:41 +00:00
vector . append ( fd ) ;
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-07-18 15:39:49 +00:00
if ( int error = transfer_fds ( params - > writefds , wfds ) )
2019-01-30 18:01:31 +00:00
return error ;
2019-07-18 15:39:49 +00:00
if ( int error = transfer_fds ( params - > readfds , rfds ) )
2019-01-30 18:01:31 +00:00
return error ;
2019-07-18 15:39:49 +00:00
if ( int error = transfer_fds ( params - > exceptfds , efds ) )
2019-02-26 23:02:01 +00:00
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-07-18 15:39:49 +00:00
dbgprintf ( " %s<%u> selecting on (read:%u, write:%u), timeout=%p \n " , name ( ) . characters ( ) , pid ( ) , rfds . size ( ) , wfds . size ( ) , params - > timeout ) ;
2019-01-16 16:20:58 +00:00
# endif
2019-07-21 11:31:20 +00:00
if ( ! params - > timeout | | select_has_timeout ) {
if ( current - > block < Thread : : SelectBlocker > ( timeout , select_has_timeout , rfds , wfds , efds ) = = Thread : : BlockResult : : InterruptedBySignal )
return - EINTR ;
}
2019-01-15 22:12:20 +00:00
2019-06-06 15:46:41 +00:00
int marked_fd_count = 0 ;
2019-06-07 09:43:58 +00:00
auto mark_fds = [ & ] ( auto * fds , auto & vector , auto should_mark ) {
2019-06-06 15:46:41 +00:00
if ( ! fds )
return ;
FD_ZERO ( fds ) ;
for ( int fd : vector ) {
2019-06-13 20:03:04 +00:00
if ( auto * description = file_description ( fd ) ; description & & should_mark ( * description ) ) {
2019-06-06 15:46:41 +00:00
FD_SET ( fd , fds ) ;
+ + marked_fd_count ;
2019-01-15 22:12:20 +00:00
}
}
2019-06-06 15:46:41 +00:00
} ;
2019-07-18 15:39:49 +00:00
mark_fds ( params - > readfds , rfds , [ ] ( auto & description ) { return description . can_read ( ) ; } ) ;
mark_fds ( params - > writefds , wfds , [ ] ( auto & description ) { return description . can_write ( ) ; } ) ;
2019-06-06 15:46:41 +00:00
// FIXME: We should also mark params->exceptfds as appropriate.
2019-07-20 09:05:52 +00:00
2019-06-06 15:46:41 +00:00
return marked_fd_count ;
2019-01-15 22:12:20 +00:00
}
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-07-19 07:04:12 +00:00
Thread : : SelectBlocker : : FDVector rfds ;
Thread : : SelectBlocker : : FDVector wfds ;
2019-07-18 15:39:49 +00:00
2019-01-23 07:03:31 +00:00
for ( int i = 0 ; i < nfds ; + + i ) {
if ( fds [ i ] . events & POLLIN )
2019-07-18 15:39:49 +00:00
rfds . append ( fds [ i ] . fd ) ;
2019-01-23 07:03:31 +00:00
if ( fds [ i ] . events & POLLOUT )
2019-07-18 15:39:49 +00:00
wfds . append ( fds [ i ] . fd ) ;
2019-01-23 07:03:31 +00:00
}
2019-07-18 15:39:49 +00:00
timeval actual_timeout ;
bool has_timeout = false ;
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 ;
2019-07-18 15:39:49 +00:00
timeval_add ( kgettimeofday ( ) , tvtimeout , actual_timeout ) ;
has_timeout = true ;
2019-05-18 01:59:48 +00:00
}
2019-05-19 08:24:28 +00:00
# if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
2019-07-18 15:39:49 +00:00
dbgprintf ( " %s<%u> polling on (read:%u, write:%u), timeout=%d \n " , name ( ) . characters ( ) , pid ( ) , rfds . size ( ) , wfds . size ( ) , timeout ) ;
2019-05-19 08:24:28 +00:00
# endif
2019-08-02 13:18:47 +00:00
if ( has_timeout | | timeout < 0 ) {
2019-07-21 11:31:20 +00:00
if ( current - > block < Thread : : SelectBlocker > ( actual_timeout , has_timeout , rfds , wfds , Thread : : SelectBlocker : : FDVector ( ) ) = = Thread : : BlockResult : : InterruptedBySignal )
return - EINTR ;
}
2019-01-23 07:03:31 +00:00
int fds_with_revents = 0 ;
for ( int i = 0 ; i < nfds ; + + i ) {
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fds [ i ] . fd ) ;
if ( ! description ) {
2019-01-23 07:03:31 +00:00
fds [ i ] . revents = POLLNVAL ;
continue ;
}
fds [ i ] . revents = 0 ;
2019-06-13 20:03:04 +00:00
if ( fds [ i ] . events & POLLIN & & description - > can_read ( ) )
2019-01-23 07:03:31 +00:00
fds [ i ] . revents | = POLLIN ;
2019-06-13 20:03:04 +00:00
if ( fds [ i ] . events & POLLOUT & & description - > 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-05-30 18:23:50 +00:00
Custody & Process : : current_directory ( )
2019-01-16 16:20:58 +00:00
{
2019-05-30 18:23:50 +00:00
if ( ! m_cwd )
m_cwd = VFS : : the ( ) . root_custody ( ) ;
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . link ( StringView ( old_path ) , StringView ( new_path ) , current_directory ( ) ) ;
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . unlink ( StringView ( pathname ) , current_directory ( ) ) ;
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . symlink ( StringView ( target ) , StringView ( linkpath ) , current_directory ( ) ) ;
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . rmdir ( StringView ( pathname ) , current_directory ( ) ) ;
2019-01-28 03:16:01 +00:00
}
2019-07-03 19:17:35 +00:00
int Process : : sys $ read_tsc ( u32 * lsw , u32 * msw )
2019-01-25 01:09:29 +00:00
{
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . chmod ( StringView ( pathname ) , mode , current_directory ( ) ) ;
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 )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2019-03-01 09:39:19 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
return description - > fchmod ( mode ) ;
2019-03-01 09:39:19 +00:00
}
2019-06-01 18:31:36 +00:00
int Process : : sys $ fchown ( int fd , uid_t uid , gid_t gid )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2019-06-01 18:31:36 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
return description - > chown ( uid , gid ) ;
2019-06-01 18:31:36 +00:00
}
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . chown ( StringView ( pathname ) , uid , gid , current_directory ( ) ) ;
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-05-31 05:19:54 +00:00
m_executable = nullptr ;
m_cwd = nullptr ;
2019-05-31 06:03:58 +00:00
m_elf_loader = 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 ;
2019-06-07 09:43:58 +00:00
for_each_thread ( [ ] ( Thread & thread ) {
2019-03-23 21:03:17 +00:00
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 ) {
2019-06-27 11:34:28 +00:00
amount + = region . size ( ) ;
2019-02-03 17:53:18 +00:00
}
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 ) {
2019-06-27 11:34:28 +00:00
amount + = region . amount_resident ( ) ;
2019-02-03 17:53:18 +00:00
}
return amount ;
}
size_t Process : : amount_shared ( ) const
{
// FIXME: This will double count if multiple regions use the same physical page.
2019-06-21 16:40:24 +00:00
// FIXME: It doesn't work at the moment, since it relies on PhysicalPage ref counts,
2019-06-21 13:29:31 +00:00
// and each PhysicalPage is only reffed by its VMObject. This needs to be refactored
2019-06-21 16:40:24 +00:00
// so that every Region contributes +1 ref to each of its PhysicalPages.
2019-02-03 17:53:18 +00:00
size_t amount = 0 ;
for ( auto & region : m_regions ) {
2019-06-27 11:34:28 +00:00
amount + = region . amount_shared ( ) ;
2019-02-03 17:53:18 +00:00
}
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 ( ) ;
2019-06-13 20:03:04 +00:00
auto description = FileDescription : : 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 )
2019-06-13 20:03:04 +00:00
description - > set_blocking ( false ) ;
m_fds [ fd ] . set ( move ( description ) , 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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-02-14 13:38:30 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-02-14 13:38:30 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > 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-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-02-14 14:17:30 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-02-14 14:17:30 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-08-11 13:38:20 +00:00
return socket . listen ( backlog ) ;
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-06-13 20:03:04 +00:00
auto * accepting_socket_description = file_description ( accepting_socket_fd ) ;
if ( ! accepting_socket_description )
2019-02-14 14:17:30 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! accepting_socket_description - > is_socket ( ) )
2019-02-14 14:17:30 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * accepting_socket_description - > socket ( ) ;
2019-02-14 14:17:30 +00:00
if ( ! socket . can_accept ( ) ) {
2019-07-18 08:39:00 +00:00
if ( accepting_socket_description - > is_blocking ( ) ) {
2019-07-20 09:05:52 +00:00
if ( current - > block < Thread : : AcceptBlocker > ( * accepting_socket_description ) = = Thread : : BlockResult : : InterruptedBySignal )
2019-07-18 08:39:00 +00:00
return - EINTR ;
} else {
return - EAGAIN ;
}
2019-02-14 14:17:30 +00:00
}
2019-02-15 10:43:43 +00:00
auto accepted_socket = socket . accept ( ) ;
ASSERT ( accepted_socket ) ;
2019-08-10 02:25:30 +00:00
bool success = accepted_socket - > get_peer_address ( address , address_size ) ;
2019-02-14 14:40:04 +00:00
ASSERT ( success ) ;
2019-08-11 13:38:20 +00:00
auto accepted_socket_description = FileDescription : : create ( * accepted_socket ) ;
2019-02-15 10:43:43 +00:00
// 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.
2019-06-13 20:03:04 +00:00
accepted_socket_description - > set_blocking ( accepting_socket_description - > is_blocking ( ) ) ;
m_fds [ accepted_socket_fd ] . set ( move ( accepted_socket_description ) , m_fds [ accepting_socket_fd ] . flags ) ;
2019-10-08 19:41:46 +00:00
// NOTE: Moving this state to Completed is what causes connect() to unblock on the client side.
accepted_socket - > set_setup_state ( Socket : : SetupState : : Completed ) ;
2019-02-15 10:43:43 +00:00
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-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-02-14 14:55:19 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-02-14 14:55:19 +00:00
return - ENOTSOCK ;
2019-08-11 13:38:20 +00:00
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-08-11 13:38:20 +00:00
return socket . connect ( * description , address , address_size , description - > is_blocking ( ) ? ShouldBlock : : Yes : ShouldBlock : : No ) ;
2019-02-14 16:18:35 +00:00
}
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-03-12 14:51:42 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-03-12 14:51:42 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-03-12 14:51:42 +00:00
kprintf ( " sendto %p (%u), flags=%u, addr: %p (%u) \n " , data , data_length , flags , addr , addr_length ) ;
2019-06-13 20:03:04 +00:00
return socket . sendto ( * description , 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 ) {
2019-06-07 09:43:58 +00:00
return - EINVAL ;
2019-03-13 22:14:30 +00:00
}
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-03-12 16:27:07 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-03-12 16:27:07 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-05-20 01:44:45 +00:00
2019-06-13 20:03:04 +00:00
bool original_blocking = description - > is_blocking ( ) ;
2019-05-20 01:44:45 +00:00
if ( flags & MSG_DONTWAIT )
2019-06-13 20:03:04 +00:00
description - > set_blocking ( false ) ;
2019-05-20 01:44:45 +00:00
2019-06-13 20:03:04 +00:00
auto nrecv = socket . recvfrom ( * description , buffer , buffer_length , flags , addr , addr_length ) ;
2019-05-20 01:44:45 +00:00
if ( flags & MSG_DONTWAIT )
2019-06-13 20:03:04 +00:00
description - > set_blocking ( original_blocking ) ;
2019-05-20 01:44:45 +00:00
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-05-19 17:55:27 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-05-19 17:55:27 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-05-20 18:33:03 +00:00
if ( ! socket . get_local_address ( addr , addrlen ) )
return - EINVAL ; // FIXME: Should this be another error? I'm not sure.
return 0 ;
}
int Process : : sys $ getpeername ( 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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-05-20 18:33:03 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-05-20 18:33:03 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-05-20 18:33:03 +00:00
2019-08-10 03:17:00 +00:00
if ( socket . setup_state ( ) ! = Socket : : SetupState : : Completed )
2019-05-23 13:39:52 +00:00
return - ENOTCONN ;
2019-05-20 18:33:03 +00:00
if ( ! socket . get_peer_address ( addr , addrlen ) )
2019-05-19 17:55:27 +00:00
return - EINVAL ; // FIXME: Should this be another error? I'm not sure.
return 0 ;
}
2019-05-29 21:20:51 +00:00
int Process : : sys $ sched_setparam ( pid_t pid , const struct sched_param * param )
{
if ( ! validate_read_typed ( param ) )
return - EFAULT ;
InterruptDisabler disabler ;
auto * peer = this ;
if ( pid ! = 0 )
peer = Process : : from_pid ( pid ) ;
if ( ! peer )
return - ESRCH ;
if ( ! is_superuser ( ) & & m_euid ! = peer - > m_uid & & m_uid ! = peer - > m_uid )
return - EPERM ;
if ( param - > sched_priority < Process : : FirstPriority | | param - > sched_priority > Process : : LastPriority )
return - EINVAL ;
peer - > set_priority ( Priority ( param - > sched_priority ) ) ;
return 0 ;
}
int Process : : sys $ sched_getparam ( pid_t pid , struct sched_param * param )
{
if ( ! validate_read_typed ( param ) )
return - EFAULT ;
InterruptDisabler disabler ;
auto * peer = this ;
if ( pid ! = 0 )
peer = Process : : from_pid ( pid ) ;
if ( ! peer )
return - ESRCH ;
if ( ! is_superuser ( ) & & m_euid ! = peer - > m_uid & & m_uid ! = peer - > m_uid )
return - EPERM ;
param - > sched_priority = peer - > priority ( ) ;
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-03-13 12:13:23 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-03-13 12:13:23 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-03-13 12:13:23 +00:00
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 ;
2019-06-13 20:03:04 +00:00
auto * description = file_description ( sockfd ) ;
if ( ! description )
2019-03-13 12:13:23 +00:00
return - EBADF ;
2019-06-13 20:03:04 +00:00
if ( ! description - > is_socket ( ) )
2019-03-13 12:13:23 +00:00
return - ENOTSOCK ;
2019-06-13 20:03:04 +00:00
auto & socket = * description - > socket ( ) ;
2019-03-13 12:13:23 +00:00
return socket . setsockopt ( level , option , value , value_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-07-18 07:52:22 +00:00
int Process : : sys $ create_shared_buffer ( 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 ( ! validate_write_typed ( buffer ) )
return - EFAULT ;
2019-07-15 18:38:41 +00:00
2019-02-16 11:13:43 +00:00
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
2019-07-16 13:03:39 +00:00
static int s_next_shared_buffer_id ;
2019-02-16 11:13:43 +00:00
int shared_buffer_id = + + s_next_shared_buffer_id ;
2019-07-15 18:38:41 +00:00
auto shared_buffer = make < SharedBuffer > ( shared_buffer_id , size ) ;
shared_buffer - > share_with ( m_pid ) ;
2019-07-19 15:46:21 +00:00
* buffer = shared_buffer - > ref_for_process_and_get_address ( * this ) ;
2019-06-22 14:22:34 +00:00
ASSERT ( ( int ) shared_buffer - > size ( ) > = size ) ;
2019-02-16 23:13:47 +00:00
# ifdef SHARED_BUFFER_DEBUG
2019-07-15 18:38:41 +00:00
kprintf ( " %s(%u): Created shared buffer %d @ %p (%u bytes, vmo is %u) \n " , name ( ) . characters ( ) , pid ( ) , shared_buffer_id , * buffer , size , shared_buffer - > size ( ) ) ;
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 ) ) ;
2019-07-15 18:38:41 +00:00
2019-02-16 11:13:43 +00:00
return shared_buffer_id ;
}
2019-07-18 07:52:22 +00:00
int Process : : sys $ share_buffer_with ( int shared_buffer_id , pid_t peer_pid )
{
if ( ! peer_pid | | peer_pid < 0 | | peer_pid = = m_pid )
return - EINVAL ;
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-07-28 05:11:14 +00:00
if ( ! shared_buffer . is_shared_with ( m_pid ) )
return - EPERM ;
2019-07-18 07:52:22 +00:00
{
InterruptDisabler disabler ;
auto * peer = Process : : from_pid ( peer_pid ) ;
if ( ! peer )
return - ESRCH ;
}
shared_buffer . share_with ( peer_pid ) ;
return 0 ;
}
2019-07-29 05:26:01 +00:00
int Process : : sys $ share_buffer_globally ( 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 . is_shared_with ( m_pid ) )
return - EPERM ;
shared_buffer . share_globally ( ) ;
return 0 ;
}
2019-02-16 11:13:43 +00:00
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-07-28 05:11:14 +00:00
if ( ! shared_buffer . is_shared_with ( m_pid ) )
return - EPERM ;
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-07-19 15:46:21 +00:00
shared_buffer . deref_for_process ( * this ) ;
2019-02-16 11:13:43 +00:00
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 ;
2019-07-15 18:38:41 +00:00
if ( ! shared_buffer . is_shared_with ( m_pid ) )
2019-07-28 05:11:14 +00:00
return ( void * ) - EPERM ;
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-07-19 15:46:21 +00:00
return shared_buffer . ref_for_process_and_get_address ( * this ) ;
2019-02-16 11:13:43 +00:00
}
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 ;
2019-07-15 18:38:41 +00:00
if ( ! shared_buffer . is_shared_with ( m_pid ) )
2019-07-28 05:11:14 +00:00
return - EPERM ;
2019-03-08 11:22:55 +00:00
# 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 ;
2019-07-15 18:38:41 +00:00
if ( ! shared_buffer . is_shared_with ( m_pid ) )
2019-07-28 05:11:14 +00:00
return - EPERM ;
2019-03-08 11:22:55 +00:00
# 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-06-07 09:43:58 +00:00
case Process : : IdlePriority :
return " Idle " ;
case Process : : LowPriority :
return " Low " ;
case Process : : NormalPriority :
return " Normal " ;
case Process : : HighPriority :
return " High " ;
2019-03-05 09:34:08 +00:00
}
kprintf ( " to_string(Process::Priority): Invalid priority: %u \n " , priority ) ;
ASSERT_NOT_REACHED ( ) ;
return nullptr ;
}
2019-03-23 21:03:17 +00:00
2019-07-03 19:17:35 +00:00
void Process : : terminate_due_to_signal ( u8 signal )
2019-03-23 21:03:17 +00:00
{
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 ( ) ;
}
2019-07-03 19:17:35 +00:00
void Process : : send_signal ( u8 signal , Process * sender )
2019-03-23 21:03:17 +00:00
{
// 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 ;
2019-06-07 09:43:58 +00:00
for_each_thread ( [ & count ] ( auto & ) {
2019-03-23 21:03:17 +00:00
+ + count ;
return IterationDecision : : Continue ;
} ) ;
return count ;
}
2019-03-23 21:59:08 +00:00
2019-06-07 09:43:58 +00:00
int Process : : sys $ create_thread ( int ( * entry ) ( void * ) , void * argument )
2019-03-23 21:59:08 +00:00
{
if ( ! validate_read ( ( const void * ) entry , sizeof ( void * ) ) )
return - EFAULT ;
auto * thread = new Thread ( * this ) ;
auto & tss = thread - > tss ( ) ;
2019-07-03 19:17:35 +00:00
tss . eip = ( u32 ) entry ;
2019-03-23 21:59:08 +00:00
tss . eflags = 0x0202 ;
tss . cr3 = page_directory ( ) . cr3 ( ) ;
thread - > make_userspace_stack_for_secondary_thread ( argument ) ;
2019-09-07 13:50:44 +00:00
thread - > make_thread_specific_region ( { } ) ;
2019-03-23 21:59:08 +00:00
thread - > set_state ( Thread : : State : : Runnable ) ;
2019-07-14 08:17:58 +00:00
return thread - > tid ( ) ;
2019-03-23 21:59:08 +00:00
}
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 ;
2019-06-07 09:43:58 +00:00
for_each_thread ( [ & ] ( Thread & thread ) {
2019-03-25 12:03:49 +00:00
if ( thread . tid ( ) = = tid ) {
beneficiary = & thread ;
2019-06-07 15:13:23 +00:00
return IterationDecision : : Break ;
2019-03-25 12:03:49 +00:00
}
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-05-30 18:23:50 +00:00
return VFS : : the ( ) . rename ( StringView ( oldpath ) , StringView ( newpath ) , current_directory ( ) ) ;
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 ( ) ;
2019-08-11 07:32:21 +00:00
auto description = FileDescription : : create ( shm_or_error . value ( ) ) ;
2019-06-13 20:03:04 +00:00
m_fds [ fd ] . set ( move ( description ) , FD_CLOEXEC ) ;
2019-04-09 00:37:05 +00:00
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 )
{
2019-06-13 20:03:04 +00:00
auto * description = file_description ( fd ) ;
if ( ! description )
2019-04-08 23:10:00 +00:00
return - EBADF ;
// FIXME: Check that fd is writable, otherwise EINVAL.
2019-06-13 20:03:04 +00:00
return description - > truncate ( length ) ;
2019-04-08 23:10:00 +00:00
}
2019-04-22 16:44:45 +00:00
2019-07-22 18:01:11 +00:00
int Process : : sys $ watch_file ( const char * path , int path_length )
{
if ( ! validate_read ( path , path_length ) )
return - EFAULT ;
auto custody_or_error = VFS : : the ( ) . resolve_path ( { path , path_length } , current_directory ( ) ) ;
if ( custody_or_error . is_error ( ) )
return custody_or_error . error ( ) ;
auto & custody = custody_or_error . value ( ) ;
auto & inode = custody - > inode ( ) ;
int fd = alloc_fd ( ) ;
if ( fd < 0 )
return fd ;
m_fds [ fd ] . set ( FileDescription : : create ( * InodeWatcher : : create ( inode ) ) ) ;
return fd ;
}
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 ;
2019-06-13 20:03:04 +00:00
auto description = FileDescription : : create ( peer - > ensure_tracer ( ) ) ;
m_fds [ fd ] . set ( move ( description ) , 0 ) ;
2019-04-22 16:44:45 +00:00
return fd ;
}
2019-07-19 11:08:26 +00:00
int Process : : sys $ halt ( )
{
if ( ! is_superuser ( ) )
return - EPERM ;
dbgprintf ( " acquiring FS locks... \n " ) ;
FS : : lock_all ( ) ;
dbgprintf ( " syncing mounted filesystems... \n " ) ;
FS : : sync ( ) ;
dbgprintf ( " attempting system shutdown... \n " ) ;
IO : : out16 ( 0x604 , 0x2000 ) ;
return ESUCCESS ;
}
2019-07-19 07:58:12 +00:00
int Process : : sys $ reboot ( )
{
if ( ! is_superuser ( ) )
return - EPERM ;
dbgprintf ( " acquiring FS locks... \n " ) ;
FS : : lock_all ( ) ;
dbgprintf ( " syncing mounted filesystems... \n " ) ;
FS : : sync ( ) ;
dbgprintf ( " attempting reboot via KB Controller... \n " ) ;
IO : : out8 ( 0x64 , 0xFE ) ;
return ESUCCESS ;
}
2019-08-15 16:13:56 +00:00
int Process : : sys $ mount ( const char * device_path , const char * mountpoint , const char * fstype )
2019-08-02 13:18:47 +00:00
{
2019-08-02 17:03:50 +00:00
if ( ! is_superuser ( ) )
return - EPERM ;
2019-08-15 16:13:56 +00:00
if ( ! validate_read_str ( device_path ) | | ! validate_read_str ( mountpoint ) | | ! validate_read_str ( fstype ) )
2019-08-02 13:18:47 +00:00
return - EFAULT ;
2019-08-15 16:13:56 +00:00
dbg ( ) < < " mount " < < fstype < < " : device " < < device_path < < " @ " < < mountpoint ;
2019-08-02 17:03:50 +00:00
auto custody_or_error = VFS : : the ( ) . resolve_path ( mountpoint , current_directory ( ) ) ;
if ( custody_or_error . is_error ( ) )
return custody_or_error . error ( ) ;
auto & mountpoint_custody = custody_or_error . value ( ) ;
2019-08-15 16:13:56 +00:00
RefPtr < FS > fs { nullptr } ;
2019-08-02 13:18:47 +00:00
2019-08-15 16:13:56 +00:00
if ( strcmp ( fstype , " ext2 " ) = = 0 | | strcmp ( fstype , " Ext2FS " ) = = 0 ) {
auto metadata_or_error = VFS : : the ( ) . lookup_metadata ( device_path , current_directory ( ) ) ;
if ( metadata_or_error . is_error ( ) )
return metadata_or_error . error ( ) ;
2019-08-02 13:18:47 +00:00
2019-08-15 16:13:56 +00:00
auto major = metadata_or_error . value ( ) . major_device ;
auto minor = metadata_or_error . value ( ) . minor_device ;
2019-08-02 13:18:47 +00:00
2019-08-18 11:48:15 +00:00
auto * device = Device : : get_device ( major , minor ) ;
2019-08-15 16:13:56 +00:00
if ( ! device ) {
dbg ( ) < < " mount: device ( " < < major < < " , " < < minor < < " ) not found " ;
return - ENODEV ;
}
if ( ! device - > is_disk_device ( ) ) {
dbg ( ) < < " mount: device ( " < < major < < " , " < < minor < < " ) is not a DiskDevice " ;
return - ENODEV ;
}
2019-08-02 17:30:30 +00:00
2019-08-15 16:13:56 +00:00
auto & disk_device = static_cast < DiskDevice & > ( * device ) ;
2019-08-02 17:30:30 +00:00
2019-08-15 16:13:56 +00:00
dbg ( ) < < " mount: attempting to mount device ( " < < major < < " , " < < minor < < " ) on " < < mountpoint ;
fs = Ext2FS : : create ( disk_device ) ;
} else if ( strcmp ( fstype , " proc " ) = = 0 | | strcmp ( fstype , " ProcFS " ) = = 0 )
fs = ProcFS : : create ( ) ;
else if ( strcmp ( fstype , " devpts " ) = = 0 | | strcmp ( fstype , " DevPtsFS " ) = = 0 )
fs = DevPtsFS : : create ( ) ;
else if ( strcmp ( fstype , " tmp " ) = = 0 | | strcmp ( fstype , " TmpFS " ) = = 0 )
fs = TmpFS : : create ( ) ;
else
return - ENODEV ;
2019-08-02 13:18:47 +00:00
2019-08-15 16:13:56 +00:00
if ( ! fs - > initialize ( ) ) {
dbg ( ) < < " mount: failed to initialize " < < fstype < < " filesystem on " < < device_path ;
2019-08-02 17:30:30 +00:00
return - ENODEV ;
2019-08-02 13:18:47 +00:00
}
2019-08-15 16:13:56 +00:00
auto result = VFS : : the ( ) . mount ( fs . release_nonnull ( ) , mountpoint_custody ) ;
2019-08-02 17:23:23 +00:00
dbg ( ) < < " mount: successfully mounted " < < device_path < < " on " < < mountpoint ;
2019-08-02 17:03:50 +00:00
return result ;
2019-08-02 13:18:47 +00:00
}
2019-08-11 13:56:39 +00:00
int Process : : sys $ umount ( const char * mountpoint )
{
if ( ! is_superuser ( ) )
return - EPERM ;
if ( ! validate_read_str ( mountpoint ) )
return - EFAULT ;
auto metadata_or_error = VFS : : the ( ) . lookup_metadata ( mountpoint , current_directory ( ) ) ;
if ( metadata_or_error . is_error ( ) )
return metadata_or_error . error ( ) ;
2019-08-17 12:24:50 +00:00
auto guest_inode_id = metadata_or_error . value ( ) . inode ;
return VFS : : the ( ) . unmount ( guest_inode_id ) ;
2019-08-11 13:56:39 +00:00
}
2019-04-22 16:44:45 +00:00
ProcessTracer & Process : : ensure_tracer ( )
{
if ( ! m_tracer )
m_tracer = ProcessTracer : : create ( m_pid ) ;
return * m_tracer ;
}
2019-04-29 02:55:54 +00:00
2019-06-07 07:36:51 +00:00
void Process : : FileDescriptionAndFlags : : clear ( )
2019-04-29 02:55:54 +00:00
{
2019-06-13 20:03:04 +00:00
description = nullptr ;
2019-04-29 02:55:54 +00:00
flags = 0 ;
}
2019-07-03 19:17:35 +00:00
void Process : : FileDescriptionAndFlags : : set ( NonnullRefPtr < FileDescription > & & d , u32 f )
2019-04-29 02:55:54 +00:00
{
2019-06-13 20:03:04 +00:00
description = move ( d ) ;
2019-04-29 02:55:54 +00:00
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 ;
2019-05-30 18:23:50 +00:00
return VFS : : the ( ) . mknod ( StringView ( pathname ) , mode , dev , current_directory ( ) ) ;
2019-05-03 20:59:58 +00:00
}
2019-07-21 07:59:17 +00:00
int Process : : sys $ dump_backtrace ( )
{
dump_backtrace ( ) ;
return 0 ;
}
2019-07-21 17:45:31 +00:00
int Process : : sys $ dbgputch ( u8 ch )
{
IO : : out8 ( 0xe9 , ch ) ;
return 0 ;
}
2019-07-21 19:43:37 +00:00
int Process : : sys $ dbgputstr ( const u8 * characters , int length )
{
2019-08-09 17:44:14 +00:00
if ( ! length )
return 0 ;
2019-07-21 19:43:37 +00:00
if ( ! validate_read ( characters , length ) )
return - EFAULT ;
for ( int i = 0 ; i < length ; + + i )
IO : : out8 ( 0xe9 , characters [ i ] ) ;
return 0 ;
}
2019-07-25 19:02:19 +00:00
2019-08-07 19:52:43 +00:00
KBuffer Process : : backtrace ( ProcessInspectionHandle & handle ) const
2019-07-25 19:02:19 +00:00
{
2019-08-07 19:52:43 +00:00
KBufferBuilder builder ;
2019-07-25 19:02:19 +00:00
for_each_thread ( [ & ] ( Thread & thread ) {
builder . appendf ( " Thread %d: \n " , thread . tid ( ) ) ;
builder . append ( thread . backtrace ( handle ) ) ;
return IterationDecision : : Continue ;
} ) ;
2019-08-07 19:52:43 +00:00
return builder . build ( ) ;
2019-07-25 19:02:19 +00:00
}
2019-07-29 05:26:01 +00:00
int Process : : sys $ set_process_icon ( int icon_id )
{
LOCKER ( shared_buffers ( ) . lock ( ) ) ;
auto it = shared_buffers ( ) . resource ( ) . find ( icon_id ) ;
if ( it = = shared_buffers ( ) . resource ( ) . end ( ) )
return - EINVAL ;
auto & shared_buffer = * ( * it ) . value ;
if ( ! shared_buffer . is_shared_with ( m_pid ) )
return - EPERM ;
m_icon_id = icon_id ;
return 0 ;
}
2019-08-15 18:55:10 +00:00
int Process : : sys $ get_process_name ( char * buffer , int buffer_size )
{
if ( buffer_size < = 0 )
return - EINVAL ;
if ( ! validate_write ( buffer , buffer_size ) )
return - EFAULT ;
if ( m_name . length ( ) > = buffer_size )
return - ENAMETOOLONG ;
strncpy ( buffer , m_name . characters ( ) , buffer_size ) ;
return 0 ;
}
2019-10-13 14:41:55 +00:00
// We don't use the flag yet, but we could use it for distinguishing
// random source like Linux, unlike the OpenBSD equivalent. However, if we
// do, we should be able of the caveats that Linux has dealt with.
int Process : : sys $ getrandom ( void * buffer , size_t buffer_size , unsigned int flags __attribute__ ( ( unused ) ) )
{
if ( buffer_size < = 0 )
return - EINVAL ;
if ( ! validate_write ( buffer , buffer_size ) )
return - EFAULT ;
// XXX: We probably lose a lot of entropy here, out of an already marginal
// PRNG. A better implementation would not throw away bits for the sake of
// array indexing, and use a better PRNG in the first place.
uint8_t * bytes = ( uint8_t * ) buffer ;
for ( size_t i = 0 ; i < buffer_size ; i + + )
bytes [ i ] = ( uint8_t ) ( RandomDevice : : random_value ( ) % 255 ) ;
return 0 ;
}