Add umount(2) and unmountat(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2014-05-07 14:14:38 +02:00
parent e88a3ef654
commit d890d3082d
28 changed files with 599 additions and 477 deletions

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@ -23,6 +23,7 @@
#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -49,6 +50,7 @@
#endif
#if defined(__sortix__)
#include <ioleast.h>
#include <timespec.h>
#else
struct timespec timespec_make(time_t sec, long nsec)
@ -80,6 +82,8 @@ struct timespec timespec_make(time_t sec, long nsec)
#include "ioleast.h"
#include "util.h"
static volatile bool should_terminate = false;
const uint32_t EXT2_FEATURE_COMPAT_SUPPORTED = 0;
const uint32_t EXT2_FEATURE_INCOMPAT_SUPPORTED = \
EXT2_FEATURE_INCOMPAT_FILETYPE;
@ -146,105 +150,103 @@ void StatInode(Inode* inode, struct stat* st)
#if defined(__sortix__)
bool RespondData(int svr, int chl, const void* ptr, size_t count)
bool RespondData(int chl, const void* ptr, size_t count)
{
return fsm_send(svr, chl, ptr, count) == (ssize_t) count;
return writeall(chl, ptr, count) == count;
}
bool RespondHeader(int svr, int chl, size_t type, size_t size)
bool RespondHeader(int chl, size_t type, size_t size)
{
struct fsm_msg_header hdr;
hdr.msgtype = type;
hdr.msgsize = size;
return RespondData(svr, chl, &hdr, sizeof(hdr));
return RespondData(chl, &hdr, sizeof(hdr));
}
bool RespondMessage(int svr, int chl, unsigned int type, const void* ptr,
size_t count)
bool RespondMessage(int chl, unsigned int type, const void* ptr, size_t count)
{
return RespondHeader(svr, chl, type, count) &&
RespondData(svr, chl, ptr, count);
return RespondHeader(chl, type, count) &&
RespondData(chl, ptr, count);
}
bool RespondError(int svr, int chl, int errnum)
bool RespondError(int chl, int errnum)
{
struct fsm_resp_error body;
body.errnum = errnum;
//fprintf(stderr, "extfs: sending error %i (%s)\n", errnum, strerror(errnum));
return RespondMessage(svr, chl, FSM_RESP_ERROR, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_ERROR, &body, sizeof(body));
}
bool RespondSuccess(int svr, int chl)
bool RespondSuccess(int chl)
{
struct fsm_resp_success body;
return RespondMessage(svr, chl, FSM_RESP_SUCCESS, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_SUCCESS, &body, sizeof(body));
}
bool RespondStat(int svr, int chl, struct stat* st)
bool RespondStat(int chl, struct stat* st)
{
struct fsm_resp_stat body;
body.st = *st;
return RespondMessage(svr, chl, FSM_RESP_STAT, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_STAT, &body, sizeof(body));
}
bool RespondSeek(int svr, int chl, off_t offset)
bool RespondSeek(int chl, off_t offset)
{
struct fsm_resp_lseek body;
body.offset = offset;
return RespondMessage(svr, chl, FSM_RESP_LSEEK, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_LSEEK, &body, sizeof(body));
}
bool RespondRead(int svr, int chl, const uint8_t* buf, size_t count)
bool RespondRead(int chl, const uint8_t* buf, size_t count)
{
struct fsm_resp_read body;
body.count = count;
return RespondMessage(svr, chl, FSM_RESP_READ, &body, sizeof(body)) &&
RespondData(svr, chl, buf, count);
return RespondMessage(chl, FSM_RESP_READ, &body, sizeof(body)) &&
RespondData(chl, buf, count);
}
bool RespondReadlink(int svr, int chl, const uint8_t* buf, size_t count)
bool RespondReadlink(int chl, const uint8_t* buf, size_t count)
{
struct fsm_resp_readlink body;
body.targetlen = count;
return RespondMessage(svr, chl, FSM_RESP_READLINK, &body, sizeof(body)) &&
RespondData(svr, chl, buf, count);
return RespondMessage(chl, FSM_RESP_READLINK, &body, sizeof(body)) &&
RespondData(chl, buf, count);
}
bool RespondWrite(int svr, int chl, size_t count)
bool RespondWrite(int chl, size_t count)
{
struct fsm_resp_write body;
body.count = count;
return RespondMessage(svr, chl, FSM_RESP_WRITE, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_WRITE, &body, sizeof(body));
}
bool RespondOpen(int svr, int chl, ino_t ino, mode_t type)
bool RespondOpen(int chl, ino_t ino, mode_t type)
{
struct fsm_resp_open body;
body.ino = ino;
body.type = type;
return RespondMessage(svr, chl, FSM_RESP_OPEN, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_OPEN, &body, sizeof(body));
}
bool RespondMakeDir(int svr, int chl, ino_t ino)
bool RespondMakeDir(int chl, ino_t ino)
{
struct fsm_resp_mkdir body;
body.ino = ino;
return RespondMessage(svr, chl, FSM_RESP_MKDIR, &body, sizeof(body));
return RespondMessage(chl, FSM_RESP_MKDIR, &body, sizeof(body));
}
bool RespondReadDir(int svr, int chl, struct kernel_dirent* dirent)
bool RespondReadDir(int chl, struct kernel_dirent* dirent)
{
struct fsm_resp_readdirents body;
body.ino = dirent->d_ino;
body.type = dirent->d_type;
body.namelen = dirent->d_namlen;
return RespondMessage(svr, chl, FSM_RESP_READDIRENTS, &body, sizeof(body)) &&
RespondData(svr, chl, dirent->d_name, dirent->d_namlen);
return RespondMessage(chl, FSM_RESP_READDIRENTS, &body, sizeof(body)) &&
RespondData(chl, dirent->d_name, dirent->d_namlen);
}
void HandleRefer(int svr, int chl, struct fsm_req_refer* msg, Filesystem* fs)
void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
{
(void) svr;
(void) chl;
if ( fs->num_inodes <= msg->ino )
return;
@ -252,9 +254,8 @@ void HandleRefer(int svr, int chl, struct fsm_req_refer* msg, Filesystem* fs)
inode->RemoteRefer();
}
void HandleUnref(int svr, int chl, struct fsm_req_unref* msg, Filesystem* fs)
void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs)
{
(void) svr;
(void) chl;
if ( fs->num_inodes <= msg->ino )
return;
@ -262,32 +263,32 @@ void HandleUnref(int svr, int chl, struct fsm_req_unref* msg, Filesystem* fs)
inode->RemoteUnref();
}
void HandleSync(int svr, int chl, struct fsm_req_sync* msg, Filesystem* fs)
void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
inode->Sync();
inode->Unref();
RespondSuccess(svr, chl);
RespondSuccess(chl);
}
void HandleStat(int svr, int chl, struct fsm_req_stat* msg, Filesystem* fs)
void HandleStat(int chl, struct fsm_req_stat* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
struct stat st;
StatInode(inode, &st);
inode->Unref();
RespondStat(svr, chl, &st);
RespondStat(chl, &st);
}
void HandleChangeMode(int svr, int chl, struct fsm_req_chmod* msg, Filesystem* fs)
void HandleChangeMode(int chl, struct fsm_req_chmod* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
uint32_t req_mode = ExtModeFromHostMode(msg->mode);
uint32_t old_mode = inode->Mode();
uint32_t new_mode = (old_mode & ~S_SETABLE) | (req_mode & S_SETABLE);
@ -295,96 +296,96 @@ void HandleChangeMode(int svr, int chl, struct fsm_req_chmod* msg, Filesystem* f
inode->Unref();
}
void HandleChangeOwner(int svr, int chl, struct fsm_req_chown* msg, Filesystem* fs)
void HandleChangeOwner(int chl, struct fsm_req_chown* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
inode->SetUserId((uint32_t) msg->uid);
inode->SetGroupId((uint32_t) msg->gid);
inode->Unref();
RespondSuccess(svr, chl);
RespondSuccess(chl);
}
void HandleUTimens(int svr, int chl, struct fsm_req_utimens* msg, Filesystem* fs)
void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
inode->data->i_atime = msg->times[0].tv_sec;
inode->data->i_mtime = msg->times[1].tv_sec;
inode->Dirty();
inode->Unref();
RespondSuccess(svr, chl);
RespondSuccess(chl);
}
void HandleTruncate(int svr, int chl, struct fsm_req_truncate* msg, Filesystem* fs)
void HandleTruncate(int chl, struct fsm_req_truncate* msg, Filesystem* fs)
{
if( msg->size < 0 ) { RespondError(svr, chl, EINVAL); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if( msg->size < 0 ) { RespondError(chl, EINVAL); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
inode->Truncate((uint64_t) msg->size);
inode->Unref();
RespondSuccess(svr, chl);
RespondSuccess(chl);
}
void HandleSeek(int svr, int chl, struct fsm_req_lseek* msg, Filesystem* fs)
void HandleSeek(int chl, struct fsm_req_lseek* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
if ( msg->whence == SEEK_SET )
RespondSeek(svr, chl, msg->offset);
RespondSeek(chl, msg->offset);
else if ( msg->whence == SEEK_END )
{
off_t inode_size = inode->Size();
if ( (msg->offset < 0 && inode_size + msg->offset < 0) ||
(0 <= msg->offset && OFF_MAX - inode_size < msg->offset) )
RespondError(svr, chl, EOVERFLOW);
RespondError(chl, EOVERFLOW);
else
RespondSeek(svr, chl, msg->offset + inode_size);
RespondSeek(chl, msg->offset + inode_size);
}
else
RespondError(svr, chl, EINVAL);
RespondError(chl, EINVAL);
inode->Unref();
}
void HandleReadAt(int svr, int chl, struct fsm_req_pread* msg, Filesystem* fs)
void HandleReadAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
uint8_t* buf = (uint8_t*) malloc(msg->count);
if ( !buf ) { inode->Unref(); RespondError(svr, chl, errno); return; }
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; }
ssize_t amount = inode->ReadAt(buf, msg->count, msg->offset);
RespondRead(svr, chl, buf, amount);
RespondRead(chl, buf, amount);
inode->Unref();
free(buf);
}
void HandleWriteAt(int svr, int chl, struct fsm_req_pread* msg, Filesystem* fs)
void HandleWriteAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
const uint8_t* buf = (const uint8_t*) &msg[1];
ssize_t amount = inode->WriteAt(buf, msg->count, msg->offset);
RespondWrite(svr, chl, amount);
RespondWrite(chl, amount);
inode->Unref();
}
void HandleOpen(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
void HandleOpen(int chl, struct fsm_req_open* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->namelen+1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -396,23 +397,23 @@ void HandleOpen(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
free(path);
inode->Unref();
if ( !result ) { RespondError(svr, chl, errno); return; }
if ( !result ) { RespondError(chl, errno); return; }
RespondOpen(svr, chl, result->inode_id, result->Mode() & S_IFMT);
RespondOpen(chl, result->inode_id, result->Mode() & S_IFMT);
result->Unref();
}
void HandleMakeDir(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
void HandleMakeDir(int chl, struct fsm_req_open* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->namelen+1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -424,21 +425,21 @@ void HandleMakeDir(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
free(path);
inode->Unref();
if ( !result ) { RespondError(svr, chl, errno); return; }
if ( !result ) { RespondError(chl, errno); return; }
RespondMakeDir(svr, chl, result->inode_id);
RespondMakeDir(chl, result->inode_id);
result->Unref();
}
void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
if ( !S_ISDIR(inode->Mode()) )
{
inode->Unref();
RespondError(svr, chl, ENOTDIR);
RespondError(chl, ENOTDIR);
return;
}
union
@ -462,7 +463,7 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
if ( !block && !(block = inode->GetBlock(block_id = entry_block_id)) )
{
inode->Unref();
RespondError(svr, chl, errno);
RespondError(chl, errno);
return;
}
const uint8_t* block_data = block->block_data + entry_block_offset;
@ -480,7 +481,7 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
padding[dname_offset + kernel_entry.d_namlen] = '\0';
block->Unref();
inode->Unref();
RespondReadDir(svr, chl, &kernel_entry);
RespondReadDir(chl, &kernel_entry);
return;
}
offset += entry->reclen;
@ -489,29 +490,29 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
block->Unref();
kernel_entry.d_reclen = sizeof(kernel_entry);
RespondReadDir(svr, chl, &kernel_entry);
RespondReadDir(chl, &kernel_entry);
}
void HandleIsATTY(int svr, int chl, struct fsm_req_isatty* msg, Filesystem* fs)
void HandleIsATTY(int chl, struct fsm_req_isatty* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
RespondError(svr, chl, ENOTTY);
if ( !inode ) { RespondError(chl, errno); return; }
RespondError(chl, ENOTTY);
inode->Unref();
}
void HandleUnlink(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->namelen+1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -522,24 +523,24 @@ void HandleUnlink(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
free(path);
inode->Unref();
if ( !result ) { RespondError(svr, chl, errno); return; }
if ( !result ) { RespondError(chl, errno); return; }
result->Unref();
RespondSuccess(svr, chl);
RespondSuccess(chl);
}
void HandleRemoveDir(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
void HandleRemoveDir(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->namelen+1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -547,28 +548,28 @@ void HandleRemoveDir(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* f
path[msg->namelen] = '\0';
if ( inode->RemoveDirectory(path) )
RespondSuccess(svr, chl);
RespondSuccess(chl);
else
RespondError(svr, chl, errno);
RespondError(chl, errno);
free(path);
inode->Unref();
}
void HandleLink(int svr, int chl, struct fsm_req_link* msg, Filesystem* fs)
void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->linkino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
if ( fs->num_inodes <= msg->linkino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
Inode* dest = fs->GetInode((uint32_t) msg->linkino);
if ( !dest ) { inode->Unref(); RespondError(svr, chl, errno); return; }
if ( !dest ) { inode->Unref(); RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->namelen+1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -576,26 +577,26 @@ void HandleLink(int svr, int chl, struct fsm_req_link* msg, Filesystem* fs)
path[msg->namelen] = '\0';
if ( inode->Link(path, dest, false) )
RespondSuccess(svr, chl);
RespondSuccess(chl);
else
RespondError(svr, chl, errno);
RespondError(chl, errno);
free(path);
dest->Unref();
inode->Unref();
}
void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs)
void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !inode ) { RespondError(chl, errno); return; }
char* dest_raw = (char*) &(msg[1]);
char* dest = (char*) malloc(msg->targetlen + 1);
if ( !dest )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -606,7 +607,7 @@ void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs
char* path = (char*) malloc(msg->namelen + 1);
if ( !path )
{
RespondError(svr, chl, errno);
RespondError(chl, errno);
inode->Unref();
return;
}
@ -614,38 +615,38 @@ void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs
path[msg->namelen] = '\0';
if ( inode->Symlink(path, dest) )
RespondSuccess(svr, chl);
RespondSuccess(chl);
else
RespondError(svr, chl, errno);
RespondError(chl, errno);
free(path);
free(dest);
inode->Unref();
}
void HandleReadlink(int svr, int chl, struct fsm_req_readlink* msg, Filesystem* fs)
void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(svr, chl, errno); return; }
if ( !EXT2_S_ISLNK(inode->Mode()) ) { RespondError(svr, chl, EINVAL); return; }
if ( !inode ) { RespondError(chl, errno); return; }
if ( !EXT2_S_ISLNK(inode->Mode()) ) { RespondError(chl, EINVAL); return; }
size_t count = inode->Size();
uint8_t* buf = (uint8_t*) malloc(count);
if ( !buf ) { inode->Unref(); RespondError(svr, chl, errno); return; }
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; }
ssize_t amount = inode->ReadAt(buf, count, 0);
RespondReadlink(svr, chl, buf, amount);
RespondReadlink(chl, buf, amount);
inode->Unref();
free(buf);
}
void HandleRename(int svr, int chl, struct fsm_req_rename* msg, Filesystem* fs)
void HandleRename(int chl, struct fsm_req_rename* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->olddirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->newdirino ) { RespondError(svr, chl, EBADF); return; }
if ( fs->num_inodes <= msg->olddirino ) { RespondError(chl, EBADF); return; }
if ( fs->num_inodes <= msg->newdirino ) { RespondError(chl, EBADF); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->oldnamelen+1 + msg->newnamelen+1);
if ( !path ) { RespondError(svr, chl, errno); return; }
if ( !path ) { RespondError(chl, errno); return; }
memcpy(path, pathraw, msg->oldnamelen);
path[msg->oldnamelen] = '\0';
memcpy(path + msg->oldnamelen + 1, pathraw + msg->oldnamelen, msg->newnamelen);
@ -655,24 +656,23 @@ void HandleRename(int svr, int chl, struct fsm_req_rename* msg, Filesystem* fs)
const char* newname = path + msg->oldnamelen + 1;
Inode* olddir = fs->GetInode((uint32_t) msg->olddirino);
if ( !olddir ) { free(path); RespondError(svr, chl, errno); return; }
if ( !olddir ) { free(path); RespondError(chl, errno); return; }
Inode* newdir = fs->GetInode((uint32_t) msg->newdirino);
if ( !newdir ) { olddir->Unref(); free(path); RespondError(svr, chl, errno); return; }
if ( !newdir ) { olddir->Unref(); free(path); RespondError(chl, errno); return; }
if ( newdir->Rename(olddir, oldname, newname) )
RespondSuccess(svr, chl);
RespondSuccess(chl);
else
RespondError(svr, chl, errno);
RespondError(chl, errno);
newdir->Unref();
olddir->Unref();
free(path);
}
void HandleIncomingMessage(int svr, int chl, struct fsm_msg_header* hdr,
Filesystem* fs)
void HandleIncomingMessage(int chl, struct fsm_msg_header* hdr, Filesystem* fs)
{
typedef void (*handler_t)(int, int, void*, Filesystem*);
typedef void (*handler_t)(int, void*, Filesystem*);
handler_t handlers[FSM_MSG_NUM] = { NULL };
handlers[FSM_REQ_SYNC] = (handler_t) HandleSync;
handlers[FSM_REQ_STAT] = (handler_t) HandleStat;
@ -700,25 +700,25 @@ void HandleIncomingMessage(int svr, int chl, struct fsm_msg_header* hdr,
if ( FSM_MSG_NUM <= hdr->msgtype || !handlers[hdr->msgtype] )
{
fprintf(stderr, "extfs: message type %zu not supported!\n", hdr->msgtype);
RespondError(svr, chl, ENOTSUP);
RespondError(chl, ENOTSUP);
return;
}
uint8_t* body = (uint8_t*) malloc(hdr->msgsize);
if ( !body )
{
fprintf(stderr, "extfs: message of type %zu too large: %zu bytes\n", hdr->msgtype, hdr->msgsize);
RespondError(svr, chl, errno);
RespondError(chl, errno);
return;
}
ssize_t amount = fsm_recv(svr, chl, body, hdr->msgsize);
if ( amount < (ssize_t) hdr->msgsize )
size_t amount = readall(chl, body, hdr->msgsize);
if ( amount < hdr->msgsize )
{
fprintf(stderr, "extfs: incomplete message of type %zu: got %zi of %zu bytes\n", hdr->msgtype, amount, hdr->msgsize);
RespondError(svr, chl, errno);
RespondError(chl, errno);
free(body);
return;
}
handlers[hdr->msgtype](svr, chl, body, fs);
handlers[hdr->msgtype](chl, body, fs);
free(body);
}
@ -726,7 +726,6 @@ void AlarmHandler(int)
{
}
static volatile bool should_terminate = false;
void TerminationHandler(int)
{
should_terminate = true;
@ -1471,32 +1470,22 @@ int main(int argc, char* argv[])
for ( size_t i = 0; i < fs->num_groups; i++ )
fs->block_groups[i] = NULL;
#if defined(__sortix__)
if ( !mount_path )
return 0;
// Open the mount point.
int mountfd = open(mount_path, O_RDWR | O_DIRECTORY);
if ( mountfd < 0 )
error(1, errno, "%s", mount_path);
#if defined(__sortix__)
// Stat the root inode.
struct stat root_inode_st;
Inode* root_inode = fs->GetInode((uint32_t) EXT2_ROOT_INO);
if ( !root_inode )
error(1, errno, "GetInode(%u)", EXT2_ROOT_INO);
StatInode(root_inode, &root_inode_st);
root_inode->Unref();
// Create a filesystem server connected to the kernel that we'll listen on.
int serverfd = fsm_mkserver();
int serverfd = fsm_mountat(AT_FDCWD, mount_path, &root_inode_st, 0);
if ( serverfd < 0 )
error(1, errno, "fsm_mkserver");
// Create a file descriptor for our root directory. The kernel won't send
// a message to this file descriptor so we can mount it before starting to
// listen for messages.
int rootfd = fsm_bootstraprootfd(serverfd, EXT2_ROOT_INO, O_RDWR | O_CREAT,
S_IFDIR);
if ( rootfd < 0 )
error(1, errno, "fsm_bootstraprootfd");
if ( fsm_fsbind(rootfd, mountfd, 0) < 0 )
error(1, errno, "fsm_fsbind");
close(mountfd);
error(1, errno, "%s", mount_path);
// Make sure the server isn't unexpectedly killed and data is lost.
signal(SIGINT, TerminationHandler);
@ -1506,7 +1495,10 @@ int main(int argc, char* argv[])
// Become a background process in its own process group by default.
if ( !foreground )
{
if ( fork() )
pid_t child_pid = fork();
if ( child_pid < 0 )
error(1, errno, "fork");
if ( child_pid )
exit(0);
setpgid(0, 0);
}
@ -1515,20 +1507,20 @@ int main(int argc, char* argv[])
struct timespec last_sync_at;
clock_gettime(CLOCK_MONOTONIC, &last_sync_at);
int channel;
while ( 0 <= (channel = fsm_listen(serverfd)) )
while ( 0 <= (channel = accept(serverfd, NULL, NULL)) )
{
if ( should_terminate )
break;
struct fsm_msg_header hdr;
ssize_t amount;
if ( (amount = fsm_recv(serverfd, channel, &hdr, sizeof(hdr))) != sizeof(hdr) )
size_t amount;
if ( (amount = readall(channel, &hdr, sizeof(hdr))) != sizeof(hdr) )
{
error(0, errno, "incomplete header: got %zi of %zu bytes", amount, sizeof(hdr));
errno = 0;
continue;
}
HandleIncomingMessage(serverfd, channel, &hdr, fs);
fsm_closechannel(serverfd, channel);
HandleIncomingMessage(channel, &hdr, fs);
close(channel);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@ -1549,7 +1541,7 @@ int main(int argc, char* argv[])
fprintf(stderr, " done.\n");
}
fsm_closeserver(serverfd);
close(serverfd);
#elif defined(__linux__)

View File

@ -26,14 +26,17 @@
#include <assert.h>
#include <errno.h>
#include <fsmarshall-msg.h>
#include <stdint.h>
#include <string.h>
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/mount.h>
#include <sortix/seek.h>
#include <sortix/stat.h>
#include <sortix/kernel/copy.h>
#include <sortix/kernel/descriptor.h>
#include <sortix/kernel/fsfunc.h>
#include <sortix/kernel/inode.h>
@ -109,17 +112,40 @@ Ref<Descriptor> OpenDirContainingPath(ioctx_t* ctx,
// TODO: Add security checks.
Descriptor::Descriptor()
{
current_offset_lock = KTHREAD_MUTEX_INITIALIZER;
this->vnode = Ref<Vnode>(NULL);
this->ino = 0;
this->dev = 0;
this->type = 0;
this->dflags = 0;
checked_seekable = false;
seekable = false /* unused */;
current_offset = 0;
}
Descriptor::Descriptor(Ref<Vnode> vnode, int dflags)
{
current_offset_lock = KTHREAD_MUTEX_INITIALIZER;
this->vnode = Ref<Vnode>(NULL);
this->ino = 0;
this->dev = 0;
this->type = 0;
this->dflags = 0;
checked_seekable = false;
seekable = false /* unused */;
current_offset = 0;
LateConstruct(vnode, dflags);
}
void Descriptor::LateConstruct(Ref<Vnode> vnode, int dflags)
{
this->vnode = vnode;
this->ino = vnode->ino;
this->dev = vnode->dev;
this->type = vnode->type;
this->dflags = dflags;
checked_seekable = false;
seekable = false /* unused */;
current_offset = 0;
}
Descriptor::~Descriptor()
@ -749,4 +775,60 @@ ssize_t Descriptor::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer
return vnode->tcsetblob(ctx, name, buffer, count);
}
int Descriptor::unmount(ioctx_t* ctx, const char* filename, int flags)
{
if ( flags & ~(UNMOUNT_FORCE | UNMOUNT_DETACH | UNMOUNT_NOFOLLOW) )
return errno = EINVAL, -1;
int subflags = flags & ~(UNMOUNT_NOFOLLOW);
char* final;
// TODO: This may follow a symlink when not supposed to!
Ref<Descriptor> dir =
OpenDirContainingPath(ctx, Ref<Descriptor>(this), filename, &final);
if ( !dir )
return -1;
if ( !(flags & UNMOUNT_NOFOLLOW) )
{
// TODO: Potentially follow a symlink here!
}
int ret = dir->vnode->unmount(ctx, final, subflags);
delete[] final;
return ret;
}
int Descriptor::fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags)
{
return vnode->fsm_fsbind(ctx, target->vnode, flags);
}
Ref<Descriptor> Descriptor::fsm_mount(ioctx_t* ctx,
const char* filename,
const struct stat* rootst,
int flags)
{
if ( flags & ~(FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK) )
return errno = EINVAL, Ref<Descriptor>(NULL);
int result_dflags = O_READ | O_WRITE;
if ( flags & FSM_MOUNT_NOFOLLOW ) result_dflags |= O_NONBLOCK;
int subflags = flags & ~(FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK);
char* final;
// TODO: This may follow a symlink when not supposed to!
Ref<Descriptor> dir =
OpenDirContainingPath(ctx, Ref<Descriptor>(this), filename, &final);
if ( !dir )
return errno = EINVAL, Ref<Descriptor>(NULL);
if ( !(flags & FSM_MOUNT_NOFOLLOW) )
{
// TODO: Potentially follow a symlink here!
}
Ref<Descriptor> result(new Descriptor());
if ( !result )
return Ref<Descriptor>(NULL);
Ref<Vnode> result_vnode = dir->vnode->fsm_mount(ctx, final, rootst, subflags);
delete[] final;
if ( !result_vnode )
return Ref<Descriptor>(NULL);
result->LateConstruct(result_vnode, result_dflags);
return result;
}
} // namespace Sortix

View File

@ -158,8 +158,9 @@ public:
Server();
virtual ~Server();
void Disconnect();
void Unmount();
Channel* Connect();
Channel* Listen();
Channel* Accept();
Ref<Inode> BootstrapNode(ino_t ino, mode_t type);
Ref<Inode> OpenNode(ino_t ino, mode_t type);
@ -171,6 +172,7 @@ private:
uintptr_t connecter_system_tid;
Channel* connecting;
bool disconnected;
bool unmounted;
};
@ -179,8 +181,8 @@ class ServerNode : public AbstractInode
public:
ServerNode(Ref<Server> server);
virtual ~ServerNode();
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
virtual Ref<Inode> accept(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
int flags);
private:
Ref<Server> server;
@ -248,6 +250,7 @@ public:
const void* option_value, size_t option_size);
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int unmounted(ioctx_t* ctx);
private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
@ -527,6 +530,7 @@ Server::Server()
listener_system_tid = 0;
connecting = NULL;
disconnected = false;
unmounted = false;
}
Server::~Server()
@ -540,6 +544,13 @@ void Server::Disconnect()
kthread_cond_signal(&connectable_cond);
}
void Server::Unmount()
{
ScopedLock lock(&connect_lock);
unmounted = true;
kthread_cond_signal(&connecting_cond);
}
Channel* Server::Connect()
{
Channel* channel = new Channel();
@ -565,13 +576,15 @@ Channel* Server::Connect()
return channel;
}
Channel* Server::Listen()
Channel* Server::Accept()
{
ScopedLock lock(&connect_lock);
listener_system_tid = CurrentThread()->system_tid;
while ( !connecting )
while ( !connecting && !unmounted )
if ( !kthread_cond_wait_signal(&connecting_cond, &connect_lock) )
return errno = EINTR, (Channel*) NULL;
if ( unmounted )
return errno = ECONNRESET, (Channel*) NULL;
Channel* result = connecting;
connecting = NULL;
kthread_cond_signal(&connectable_cond);
@ -596,7 +609,7 @@ ServerNode::ServerNode(Ref<Server> server)
{
inode_type = INODE_TYPE_UNKNOWN;
this->server = server;
this->type = S_IFDIR;
this->type = S_IFSOCK;
this->dev = (dev_t) this;
this->ino = 0;
// TODO: Set uid, gid, mode.
@ -607,36 +620,22 @@ ServerNode::~ServerNode()
server->Disconnect();
}
Ref<Inode> ServerNode::open(ioctx_t* /*ctx*/, const char* filename, int flags,
mode_t mode)
Ref<Inode> ServerNode::accept(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
int flags)
{
unsigned long long ull_ino;
char* end;
int saved_errno = errno; errno = 0;
if ( !isspace(*filename) &&
0 < (ull_ino = strtoull(filename, &end, 10)) &&
*end == '\0' &&
errno != ERANGE )
{
errno = saved_errno;
if ( !(flags & O_CREATE) )
return errno = ENOENT, Ref<Inode>(NULL);
ino_t ino = (ino_t) ull_ino;
return server->BootstrapNode(ino, mode & S_IFMT);
}
errno = saved_errno;
if ( !strcmp(filename, "listen") )
{
Ref<ChannelNode> node(new ChannelNode);
if ( !node )
return Ref<Inode>(NULL);
Channel* channel = server->Listen();
if ( !channel )
return Ref<Inode>(NULL);
node->Construct(channel);
return node;
}
return errno = ENOENT, Ref<Inode>(NULL);
(void) addr;
(void) flags;
size_t out_addrlen = 0;
if ( addrlen && !ctx->copy_to_dest(addrlen, &out_addrlen, sizeof(out_addrlen)) )
return Ref<Inode>(NULL);
Ref<ChannelNode> node(new ChannelNode);
if ( !node )
return Ref<Inode>(NULL);
Channel* channel = server->Accept();
if ( !channel )
return Ref<Inode>(NULL);
node->Construct(channel);
return node;
}
//
@ -1443,86 +1442,31 @@ ssize_t Unode::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, siz
return ret;
}
//
// Initialization.
//
class FactoryNode : public AbstractInode
int Unode::unmounted(ioctx_t* /*ctx*/)
{
public:
FactoryNode(uid_t owner, gid_t group, mode_t mode);
virtual ~FactoryNode() { }
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
};
FactoryNode::FactoryNode(uid_t owner, gid_t group, mode_t mode)
{
inode_type = INODE_TYPE_UNKNOWN;
dev = (dev_t) this;
ino = 0;
this->type = S_IFDIR;
this->stat_uid = owner;
this->stat_gid = group;
this->stat_mode = (mode & S_SETABLE) | this->type;
server->Unmount();
return 0;
}
Ref<Inode> FactoryNode::open(ioctx_t* /*ctx*/, const char* filename,
int /*flags*/, mode_t /*mode*/)
bool Bootstrap(Ref<Inode>* out_root,
Ref<Inode>* out_server,
const struct stat* rootst)
{
if ( !strcmp(filename, "new") )
{
Ref<Server> server(new Server());
if ( !server )
return Ref<Inode>(NULL);
Ref<ServerNode> node(new ServerNode(server));
if ( !node )
return Ref<Inode>(NULL);
return node;
}
return errno = ENOENT, Ref<Inode>(NULL);
}
} // namespace UserFS
} // namespace Sortix
namespace Sortix {
int sys_fsm_fsbind(int rootfd, int mpointfd, int /*flags*/)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(rootfd);
if ( !desc ) { return -1; }
Ref<Descriptor> mpoint = CurrentProcess()->GetDescriptor(mpointfd);
if ( !mpoint ) { return -1; }
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
Ref<Inode> node = desc->vnode->inode;
return mtable->AddMount(mpoint->ino, mpoint->dev, node) ? 0 : -1;
}
} // namespace Sortix
namespace Sortix {
namespace UserFS {
void Init(const char* devpath, Ref<Descriptor> slashdev)
{
ioctx_t ctx; SetupKernelIOCtx(&ctx);
Ref<Inode> node(new FactoryNode(0, 0, 0666));
if ( !node )
PanicF("Unable to allocate %s/fs inode.", devpath);
// TODO: Race condition! Create a mkdir function that returns what it
// created, possibly with a O_MKDIR flag to open.
if ( slashdev->mkdir(&ctx, "fs", 0755) < 0 && errno != EEXIST )
PanicF("Could not create a %s/fs directory", devpath);
Ref<Descriptor> mpoint = slashdev->open(&ctx, "fs", O_READ | O_WRITE, 0);
if ( !mpoint )
PanicF("Could not open the %s/fs directory", devpath);
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
// TODO: Make sure that the mount point is *empty*! Add a proper function
// for this on the file descriptor class!
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node) )
PanicF("Unable to mount filesystem on %s/fs", devpath);
Ref<Server> server(new Server());
if ( !server )
return false;
ino_t root_inode_ino = rootst->st_ino;
mode_t root_inode_type = rootst->st_mode & S_IFMT;
Ref<Inode> root_inode = server->OpenNode(root_inode_ino, root_inode_type);
if ( !root_inode )
return false;
Ref<ServerNode> server_inode(new ServerNode(server));
if ( !server_inode )
return false;
return *out_root = root_inode, *out_server = server_inode, true;
}
} // namespace UserFS

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
This file is part of Sortix.
@ -25,10 +25,15 @@
#ifndef SORTIX_FS_USER_H
#define SORTIX_FS_USER_H
#include <sortix/stat.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/vnode.h>
namespace Sortix {
namespace UserFS {
void Init(const char* devpath, Ref<Descriptor> slashdev);
bool Bootstrap(Ref<Inode>* out_root, Ref<Inode>* out_server, const struct stat* rootst);
} // namespace UserFS
} // namespace Sortix

View File

@ -50,6 +50,10 @@ typedef struct ioctx_struct ioctx_t;
class Descriptor : public Refcountable
{
private:
Descriptor();
void LateConstruct(Ref<Vnode> vnode, int dflags);
public:
Descriptor(Ref<Vnode> vnode, int dflags);
virtual ~Descriptor();
@ -102,6 +106,10 @@ public:
const void* option_value, size_t option_size);
ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
int unmount(ioctx_t* ctx, const char* filename, int flags);
int fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags);
Ref<Descriptor> fsm_mount(ioctx_t* ctx, const char* filename,
const struct stat* rootst, int flags);
private:
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,

View File

@ -112,6 +112,7 @@ public:
const void* option_value, size_t option_size) = 0;
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count) = 0;
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count) = 0;
virtual int unmounted(ioctx_t* ctx) = 0;
};
@ -199,6 +200,7 @@ public:
const void* option_value, size_t option_size);
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int unmounted(ioctx_t* ctx);
};

View File

@ -39,6 +39,7 @@ typedef struct
Ref<Inode> inode;
ino_t ino;
dev_t dev;
bool fsbind;
} mountpoint_t;
class MountTable : public Refcountable
@ -47,7 +48,8 @@ public:
MountTable();
virtual ~MountTable();
Ref<MountTable> Fork();
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode);
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind);
bool AddMountUnlocked(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind);
public: // Consider these read-only.
kthread_mutex_t mtablelock;

View File

@ -78,6 +78,7 @@ int sys_fchroot(int);
int sys_fchrootat(int, const char*);
int sys_fcntl(int, int, uintptr_t);
int sys_fsm_fsbind(int, int, int);
int sys_fsm_mountat(int, const char*, const struct stat*, int flags);
int sys_fstat(int, struct stat*);
int sys_fstatat(int, const char*, struct stat*, int);
int sys_fstatvfs(int, struct statvfs*);
@ -166,6 +167,7 @@ int sys_timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*
int sys_truncateat(int, const char*, off_t);
mode_t sys_umask(mode_t);
int sys_unlinkat(int, const char*, int);
int sys_unmountat(int, const char*, int);
int sys_utimensat(int, const char*, const struct timespec [2], int);
pid_t sys_waitpid(pid_t, int*, int);
ssize_t sys_write(int, const void*, size_t);

View File

@ -102,6 +102,9 @@ public:
const void* option_value, size_t option_size);
ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
int unmount(ioctx_t* ctx, const char* filename, int flags);
int fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, int flags);
Ref<Vnode> fsm_mount(ioctx_t* ctx, const char* filename, const struct stat* rootst, int flags);
public /*TODO: private*/:
Ref<Inode> inode;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of Sortix.
@ -29,10 +29,9 @@
__BEGIN_DECLS
#define MREPL (0<<0) /* Replace binding. */
#define MBEFORE (1<<0) /* Add to start of directory union. */
#define MAFTER (2<<0) /* Add to end of directory union. */
#define MCREATE (1<<2) /* Create files here, otherwise try next in union. */
#define UNMOUNT_FORCE (1 << 0)
#define UNMOUNT_DETACH (1 << 1)
#define UNMOUNT_NOFOLLOW (1 << 2)
__END_DECLS

View File

@ -175,6 +175,8 @@
#define SYSCALL_GETENTROPY 147
#define SYSCALL_GETHOSTNAME 148
#define SYSCALL_SETHOSTNAME 149
#define SYSCALL_MAX_NUM 150 /* index of highest constant + 1 */
#define SYSCALL_UNMOUNTAT 150
#define SYSCALL_FSM_MOUNTAT 151
#define SYSCALL_MAX_NUM 152 /* index of highest constant + 1 */
#endif

View File

@ -406,4 +406,9 @@ ssize_t AbstractInode::tcsetblob(ioctx_t* /*ctx*/, const char* /*name*/, const v
return errno = ENOTTY, -1;
}
int AbstractInode::unmounted(ioctx_t* /*ctx*/)
{
return 0;
}
} // namespace Sortix

View File

@ -27,6 +27,7 @@
#include <assert.h>
#include <errno.h>
#include <fsmarshall-msg.h>
#include <stddef.h>
#include <stdint.h>
@ -174,7 +175,13 @@ int sys_openat(int dirfd, const char* path, int flags, mode_t mode)
if ( !desc )
return -1;
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
return dtable->Allocate(desc, fdflags);
int ret = dtable->Allocate(desc, fdflags);
if ( ret < 0 )
{
// TODO: We should use a fail-safe dtable reservation mechanism that
// causes this error earlier before we have side effects.
}
return ret;
}
// TODO: This is a hack! Stat the file in some manner and check permissions.
@ -1079,4 +1086,65 @@ int sys_shutdown(int fd, int how)
return errno = ENOSYS, -1;
}
int sys_unmountat(int dirfd, const char* path, int flags)
{
char* pathcopy = GetStringFromUser(path);
if ( !pathcopy )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
const char* relpath = pathcopy;
Ref<Descriptor> from = PrepareLookup(&relpath, dirfd);
if ( !from )
return delete[] pathcopy, -1;
int ret = from->unmount(&ctx, relpath, flags);
delete[] pathcopy;
return ret;
}
int sys_fsm_fsbind(int rootfd, int mpointfd, int flags)
{
if ( flags & ~(0) )
return errno = EINVAL, -1;
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(rootfd);
if ( !desc )
return -1;
Ref<Descriptor> mpoint = CurrentProcess()->GetDescriptor(mpointfd);
if ( !mpoint )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return mpoint->fsm_fsbind(&ctx, desc, flags);
}
int sys_fsm_mountat(int dirfd, const char* path, const struct stat* rootst, int flags)
{
if ( flags & ~(FSM_MOUNT_CLOEXEC | FSM_MOUNT_CLOFORK |
FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK) )
return -1;
int fdflags = 0;
if ( flags & FSM_MOUNT_CLOEXEC ) fdflags |= FD_CLOEXEC;
if ( flags & FSM_MOUNT_CLOFORK ) fdflags |= FD_CLOFORK;
flags &= ~(FSM_MOUNT_CLOEXEC | FSM_MOUNT_CLOFORK);
char* pathcopy = GetStringFromUser(path);
if ( !pathcopy )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
const char* relpath = pathcopy;
Ref<Descriptor> from = PrepareLookup(&relpath, dirfd);
if ( !from )
return delete[] pathcopy, -1;
Ref<Descriptor> desc = from->fsm_mount(&ctx, relpath, rootst, flags);
delete[] pathcopy;
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
int ret = dtable->Allocate(desc, fdflags);
if ( ret < 0 )
{
// TODO: We should use a fail-safe dtable reservation mechanism that
// causes this error earlier before we have side effects.
int errnum = errno;
from->unmount(&ctx, relpath, 0);
return errno = errnum, -1;
}
return ret;
}
} // namespace Sortix

View File

@ -73,7 +73,6 @@
#include "fs/full.h"
#include "fs/kram.h"
#include "fs/null.h"
#include "fs/user.h"
#include "fs/zero.h"
#include "gpu/bga/bga.h"
#include "initrd.h"
@ -601,9 +600,6 @@ static void BootThread(void* /*user*/)
// Initialize the filesystem network-
NetFS::Init("/dev", slashdev);
// Initialize the user-space filesystem framework.
UserFS::Init("/dev", slashdev);
//
// Stage 6. Executing Hosted Environment ("User-Space")
//

View File

@ -61,9 +61,14 @@ Ref<MountTable> MountTable::Fork()
return clone;
}
bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode)
bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind)
{
ScopedLock lock(&mtablelock);
return AddMountUnlocked(ino, dev, inode, fsbind);
}
bool MountTable::AddMountUnlocked(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind)
{
if ( nummounts == mountsalloced )
{
size_t newalloced = mountsalloced ? 2UL * mountsalloced : 4UL;
@ -80,6 +85,7 @@ bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode)
mp->ino = ino;
mp->dev = dev;
mp->inode = inode;
mp->fsbind = fsbind;
return true;
}

View File

@ -536,7 +536,7 @@ void Init(const char* devpath, Ref<Descriptor> slashdev)
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
// TODO: Make sure that the mount point is *empty*! Add a proper function
// for this on the file descriptor class!
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node) )
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node, false) )
PanicF("Unable to mount filesystem on %s/net/fs", devpath);
}

View File

@ -185,6 +185,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
[SYSCALL_GETENTROPY] = (void*) sys_getentropy,
[SYSCALL_GETHOSTNAME] = (void*) sys_gethostname,
[SYSCALL_SETHOSTNAME] = (void*) sys_sethostname,
[SYSCALL_UNMOUNTAT] = (void*) sys_unmountat,
[SYSCALL_FSM_MOUNTAT] = (void*) sys_fsm_mountat,
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
};
} // extern "C"

View File

@ -25,7 +25,9 @@
#include <assert.h>
#include <errno.h>
#include <sortix/fcntl.h>
#include <sortix/mount.h>
#include <sortix/stat.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/refcount.h>
@ -36,20 +38,31 @@
#include <sortix/kernel/mtable.h>
#include <sortix/kernel/process.h>
#include "fs/user.h"
namespace Sortix {
static Ref<Inode> LookupMount(Ref<Inode> inode)
static Ref<Inode> LookupMountUnlocked(Ref<Inode> inode, size_t* out_index = NULL)
{
Ref<Inode> result_inode(NULL);
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
ScopedLock lock(&mtable->mtablelock);
for ( size_t i = 0; i < mtable->nummounts; i++ )
{
mountpoint_t* mp = mtable->mounts + i;
if ( mp->ino != inode->ino || mp->dev != inode->dev )
continue;
return mp->inode;
if ( out_index )
*out_index = i;
result_inode = mp->inode;
}
return Ref<Inode>(NULL);
return result_inode;
}
static Ref<Inode> LookupMount(Ref<Inode> inode)
{
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
ScopedLock mtable_lock(&mtable->mtablelock);
return LookupMountUnlocked(inode);
}
Vnode::Vnode(Ref<Inode> inode, Ref<Vnode> mountedat, ino_t rootino, dev_t rootdev)
@ -88,7 +101,8 @@ Ref<Vnode> Vnode::open(ioctx_t* ctx, const char* filename, int flags, mode_t mod
// Move within the current filesystem.
Ref<Inode> retinode = inode->open(ctx, filename, flags, mode);
if ( !retinode ) { return Ref<Vnode>(NULL); }
if ( !retinode )
return Ref<Vnode>(NULL);
Ref<Vnode> retmountedat = mountedat;
ino_t retrootino = rootino;
dev_t retrootdev = rootdev;
@ -106,6 +120,102 @@ Ref<Vnode> Vnode::open(ioctx_t* ctx, const char* filename, int flags, mode_t mod
return Ref<Vnode>(new Vnode(retinode, retmountedat, retrootino, retrootdev));
}
int Vnode::fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, int flags)
{
(void) ctx;
if ( flags & ~(0) )
return errno = EINVAL, -1;
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
if ( !mtable->AddMount(ino, dev, target->inode, true) )
return -1;
return 0;
}
Ref<Vnode> Vnode::fsm_mount(ioctx_t* ctx,
const char* filename,
const struct stat* rootst_ptr,
int flags)
{
if ( flags & ~(0) )
return Ref<Vnode>(NULL);
if ( !strcmp(filename, ".") || !strcmp(filename, "..") )
return errno = EINVAL, Ref<Vnode>(NULL);
struct stat rootst;
if ( !ctx->copy_from_src(&rootst, rootst_ptr, sizeof(struct stat)) )
return Ref<Vnode>(NULL);
Ref<Inode> normal_inode = inode->open(ctx, filename, O_READ, 0);
if ( !normal_inode )
return Ref<Vnode>(NULL);
Ref<Inode> root_inode;
Ref<Inode> server_inode;
if ( !UserFS::Bootstrap(&root_inode, &server_inode, &rootst) )
return Ref<Vnode>(NULL);
Ref<Vnode> server_vnode(new Vnode(server_inode, Ref<Vnode>(NULL), 0, 0));
if ( !server_vnode )
return Ref<Vnode>(NULL);
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
ScopedLock lock(&mtable->mtablelock);
if ( Ref<Inode> mounted = LookupMountUnlocked(normal_inode) )
normal_inode = mounted;
if ( !mtable->AddMountUnlocked(normal_inode->ino, normal_inode->dev, root_inode, false) )
return Ref<Vnode>(NULL);
return server_vnode;
}
int Vnode::unmount(ioctx_t* ctx, const char* filename, int flags)
{
if ( flags & ~(UNMOUNT_FORCE | UNMOUNT_DETACH) )
return errno = EINVAL, -1;
if ( !strcmp(filename, ".") || !strcmp(filename, "..") )
return errno = EINVAL, -1;
Ref<Inode> normal_inode = inode->open(ctx, filename, O_READ, 0);
if ( !normal_inode )
return -1;
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
ScopedLock mtable_lock(&mtable->mtablelock);
size_t mp_index;
if ( !LookupMountUnlocked(normal_inode, &mp_index) )
return errno = EINVAL, -1;
mountpoint_t* mp = mtable->mounts + mp_index;
Ref<Inode> mp_inode = mp->inode;
bool mp_fsbind = mp->fsbind;
mp->inode.Reset();
for ( size_t n = mp_index; n < mtable->nummounts - 1; n++ )
{
mtable->mounts[n].inode.Reset();
mtable->mounts[n] = mtable->mounts[n+1];
}
if ( mp_index + 1 != mtable->nummounts )
mtable->mounts[mtable->nummounts].inode.Reset();
mtable->nummounts--;
mtable_lock.Reset();
if ( !mp_fsbind )
{
// TODO: Implement the !UNMOUNT_DETACH case.
// TODO: Implement the UNMOUNT_FORCE case.
mp_inode->unmounted(ctx);
}
mp_inode.Reset();
return 0;
}
int Vnode::sync(ioctx_t* ctx)
{
return inode->sync(ctx);

View File

@ -333,14 +333,8 @@ fcntl/creat.o \
fcntl/fcntl.o \
fcntl/openat.o \
fcntl/open.o \
fsmarshall/fsm_bootstraprootfd.o \
fsmarshall/fsm_closechannel.o \
fsmarshall/fsm_closeserver.o \
fsmarshall/fsm_fsbind.o \
fsmarshall/fsm_listen.o \
fsmarshall/fsm_mkserver.o \
fsmarshall/fsm_recv.o \
fsmarshall/fsm_send.o \
fsmarshall/fsm_mountat.o \
getopt/getopt_long.o \
getopt/getopt.o \
grp/endgrent.o \
@ -476,6 +470,8 @@ syslog/vsyslog.o \
sys/mman/mmap.o \
sys/mman/mprotect.o \
sys/mman/munmap.o \
sys/mount/unmountat.o \
sys/mount/unmount.o \
sys/readdirents/readdirents.o \
sys/resource/getpriority.o \
sys/resource/getrlimit.o \

View File

@ -1,38 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_bootstraprootfd.cpp
Creates a root file descriptor associated with a user-space filesystem.
*******************************************************************************/
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fsmarshall.h>
extern "C" int fsm_bootstraprootfd(int server, ino_t ino, int open_flags,
mode_t mode)
{
char name[sizeof(uintmax_t)*3];
snprintf(name, sizeof(name), "%ju", (uintmax_t) ino);
return openat(server, name, open_flags, mode);
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of the Sortix C Library.
@ -17,16 +17,18 @@
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_listen.cpp
Listens for a new channel on a given filesystem server.
fsmarshall/fsm_mountat.cpp
Attaches a user-space filesystem at the specified mount point.
*******************************************************************************/
#include <fcntl.h>
#include <sys/syscall.h>
#include <fsmarshall.h>
extern "C" int fsm_listen(int server)
DEFN_SYSCALL4(int, sys_fsm_mountat, SYSCALL_FSM_MOUNTAT, int, const char*, const struct stat*, int);
extern "C" int fsm_mountat(int dirfd, const char* path, const struct stat* rootst, int flags)
{
return openat(server, "listen", O_RDWR);
return sys_fsm_mountat(dirfd, path, rootst, flags);
}

View File

@ -1,32 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_recv.cpp
Reads a message from a filesystem communication channel.
*******************************************************************************/
#include <unistd.h>
#include <fsmarshall.h>
extern "C" ssize_t fsm_recv(int /*server*/, int channel, void* ptr, size_t count)
{
return read(channel, ptr, count);
}

View File

@ -1,33 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_send.cpp
Send a message to a filesystem communication channel.
*******************************************************************************/
#include <unistd.h>
#include <fsmarshall.h>
extern "C" ssize_t fsm_send(int /*server*/, int channel, const void* ptr,
size_t count)
{
return write(channel, ptr, count);
}

View File

@ -25,6 +25,8 @@
#ifndef INCLUDE_FSMARSHALL_MSG_H
#define INCLUDE_FSMARSHALL_MSG_H
#include <sys/cdefs.h>
#include <stddef.h>
#include <sortix/stat.h>
@ -32,9 +34,12 @@
#include <sortix/termios.h>
#include <sortix/timespec.h>
#if defined(__cplusplus)
extern "C" {
#endif
__BEGIN_DECLS
#define FSM_MOUNT_CLOEXEC (1 << 0)
#define FSM_MOUNT_CLOFORK (1 << 1)
#define FSM_MOUNT_NOFOLLOW (1 << 2)
#define FSM_MOUNT_NONBLOCK (1 << 3)
struct fsm_msg_header
{
@ -427,8 +432,6 @@ struct fsm_resp_tcsetblob
#define FSM_MSG_NUM 53
#if defined(__cplusplus)
} /* extern "C" */
#endif
__END_DECLS
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
This file is part of the Sortix C Library.
@ -25,29 +25,17 @@
#ifndef INCLUDE_FSMARSHALL_H
#define INCLUDE_FSMARSHALL_H
#include <stddef.h>
#include <sortix/stat.h>
#include <sortix/termios.h>
#include <sortix/timespec.h>
#include <sys/cdefs.h>
#include <fsmarshall-msg.h>
#if defined(__cplusplus)
extern "C" {
#endif
__BEGIN_DECLS
int fsm_mkserver();
int fsm_closeserver(int server);
int fsm_bootstraprootfd(int server, ino_t ino, int open_flags, mode_t mode);
int fsm_fsbind(int rootfd, int mountpoint, int flags);
int fsm_listen(int server);
int fsm_closechannel(int server, int channel);
ssize_t fsm_recv(int server, int channel, void* ptr, size_t count);
ssize_t fsm_send(int server, int channel, const void* ptr, size_t count);
struct stat;
#if defined(__cplusplus)
} /* extern "C" */
#endif
int fsm_fsbind(int, int, int);
int fsm_mountat(int, const char*, const struct stat*, int);
__END_DECLS
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of the Sortix C Library.
@ -17,16 +17,23 @@
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_closechannel.cpp
Closes a user-space filesystem communication channel.
sys/mount.h
Filesystem mount functionality.
*******************************************************************************/
#include <unistd.h>
#ifndef INCLUDE_SYS_MOUNT_H
#define INCLUDE_SYS_MOUNT_H
#include <fsmarshall.h>
#include <sys/cdefs.h>
extern "C" int fsm_closechannel(int /*server*/, int channel)
{
return close(channel);
}
#include <sortix/mount.h>
__BEGIN_DECLS
int unmount(const char*, int);
int unmountat(int, const char*, int);
__END_DECLS
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of the Sortix C Library.
@ -17,16 +17,16 @@
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_mkserver.cpp
Creates a user-space filesystem server.
sys/mount/unmount.cpp
Unmount filesystem at path.
*******************************************************************************/
#include <sys/mount.h>
#include <fcntl.h>
#include <fsmarshall.h>
extern "C" int fsm_mkserver()
extern "C" int unmount(const char* path, int flags)
{
return open("/dev/fs/new", O_RDWR | O_CREAT, 0666);
return unmountat(AT_FDCWD, path, flags);
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of the Sortix C Library.
@ -17,16 +17,17 @@
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsmarshall/fsm_closeserver.cpp
Destroys a user-space filesystem server.
sys/mount/unmountat.cpp
Unmount filesystem at path.
*******************************************************************************/
#include <unistd.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <fsmarshall.h>
DEFN_SYSCALL3(int, sys_unmountat, SYSCALL_UNMOUNTAT, int, const char*, int);
extern "C" int fsm_closeserver(int server)
extern "C" int unmountat(int dirfd, const char* path, int flags)
{
return close(server);
return sys_unmountat(dirfd, path, flags);
}