FPPS4/sys/vfs/vfs_mountroot.pas

431 lines
7.8 KiB
Plaintext

unit vfs_mountroot;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
vmount;
const
MNT_RDONLY=vmount.MNT_RDONLY;
MNT_UPDATE=vmount.MNT_UPDATE;
procedure vfs_mountroot();
function vfs_mount_path (fstype,fspath,from,opts:PChar;flags:QWORD):Integer;
function mount_mkdir (path:PChar):Integer;
function mount_rmdir (path:PChar):Integer;
function mount_into_sandbox (fstype,fspath,from,opts:PChar;flags:QWORD):Integer;
function unmount_from_sandbox(path:PChar;flags:Integer):Integer;
implementation
uses
sysutils,
errno,
vuio,
vnamei,
vnode,
vnode_if,
vfiledesc,
vfs_subr,
vfs_init,
vfs_mount,
vfs_syscalls,
kern_thr,
kern_mtx;
function strdup(src:PChar):PChar; inline;
var
i:ptrint;
begin
i:=strlen(src);
Result:=AllocMem(i+1);
Move(src^,Result^,i);
end;
function strsep(stringp:PPChar;delim:PChar):PChar;
var
b,e:PChar;
begin
b:=stringp^;
if (b=nil) then Exit(nil);
e:=strpos(b,delim)+strlen(delim);
if (e^<>#0) then
begin
e^:=#0;
Inc(e);
stringp^:=e;
end else
begin
stringp^:=nil;
end;
Result:=b;
end;
function parse_mountroot_options(ma:p_mntarg;options:PChar):p_mntarg;
var
p:PChar;
name,name_arg:PChar;
val,val_arg:PChar;
opts:PChar;
begin
if (options=nil) then
Exit(ma);
if (options[0]=#0) then
Exit(ma);
p:=strdup(options);
opts:=p;
if (opts=nil) then
begin
Exit(ma);
end;
name:=strsep(@p, ',');
while (name<>nil) do
begin
if (name[0]=#0) then
break;
val:=strscan(name, '=');
if (val<>nil) then
begin
val^:=#0;
Inc(val);
end;
name_arg:=strdup(name);
val_arg:=nil;
if (val<>nil) then
val_arg:=strdup(val);
ma:=mount_arg(ma, name_arg, val_arg, (ord(val_arg<>nil)*(-1)));
name:=strsep(@p, ',');
end;
FreeMem(opts);
Exit(ma);
end;
procedure set_rootvnode();
begin
if (VFS_ROOT(TAILQ_FIRST(@mountlist), LK_EXCLUSIVE, @rootvnode)<>0) then
begin
Assert(False,'Cannot find root vnode');
end;
VOP_UNLOCK(rootvnode, 0);
FILEDESC_XLOCK(@fd_table);
if (fd_table.fd_cdir<>nil) then
begin
vrele(fd_table.fd_cdir);
end;
fd_table.fd_cdir:=rootvnode;
VREF(rootvnode);
if (fd_table.fd_rdir<>nil) then
begin
vrele(fd_table.fd_rdir);
end;
fd_table.fd_rdir:=rootvnode;
VREF(rootvnode);
FILEDESC_XUNLOCK(@fd_table);
end;
function vfs_mountroot_devfs(mpp:pp_mount):Integer;
var
opts:p_vfsoptlist;
vfsp:p_vfsconf;
mp:p_mount;
error:Integer;
begin
mpp^:=nil;
vfsp:=vfs_byname('devfs');
Assert(vfsp<>nil,'Could not find devfs by name');
if (vfsp=nil) then
Exit(ENOENT);
mp:=vfs_mount_alloc(nil, vfsp, '/dev');
error:=vmount.VFS_MOUNT(mp);
Assert(error=0,'VFS_MOUNT(devfs) failed');
if (error<>0) then
Exit(error);
opts:=AllocMem(sizeof(vfsoptlist));
TAILQ_INIT(opts);
mp^.mnt_opt:=opts;
mtx_lock(mountlist_mtx);
TAILQ_INSERT_HEAD(@mountlist,mp,@mp^.mnt_list);
mtx_unlock(mountlist_mtx);
mpp^:=mp;
set_rootvnode();
//error:=kern_symlink('/', 'dev', UIO_SYSSPACE);
//if (error<>0) then
//begin
// Writeln('kern_symlink /dev / returns ',error);
//end;
Exit(error);
end;
procedure mount_print;
var
m:p_mount;
procedure print_vp(vp:p_vnode;const prefix:RawByteString);
var
m:p_mount;
begin
Write(prefix,':');
if (vp=nil) then
begin
Writeln(' nil');
Exit;
end;
Write(' v_tag:',vp^.v_tag);
m:=vp^.v_mount;
Writeln(
' fstype:',m^.mnt_stat.f_fstypename,
' mntfrom:',m^.mnt_stat.f_mntfromname,
' mnton:',m^.mnt_stat.f_mntonname
);
end;
begin
Writeln('[mount_print]->');
mtx_lock(mountlist_mtx);
print_vp(rootvnode,'root');
print_vp(fd_table.fd_cdir,'cdir');
print_vp(fd_table.fd_rdir,'rdir');
print_vp(fd_table.fd_jdir,'jdir');
m:=TAILQ_FIRST(@mountlist);
while (m<>nil) do
begin
Writeln(
' fstype:',m^.mnt_stat.f_fstypename,
' mntfrom:',m^.mnt_stat.f_mntfromname,
' mnton:',m^.mnt_stat.f_mntonname
);
m:=TAILQ_NEXT(m,@m^.mnt_list);
end;
mtx_unlock(mountlist_mtx);
Writeln('<-[mount_print]');
end;
function vfs_mountroot_shuffle(mpdevfs:p_mount):Integer;
var
nd:t_nameidata;
mporoot,mpnroot:p_mount;
vp,vporoot,vpdevfs:p_vnode;
//fspath:PChar;
error:Integer;
begin
mpnroot:=TAILQ_NEXT(mpdevfs,@mpdevfs^.mnt_list);
{ Shuffle the mountlist. }
mtx_lock(mountlist_mtx);
mporoot:=TAILQ_FIRST(@mountlist);
TAILQ_REMOVE(@mountlist,mpdevfs,@mpdevfs^.mnt_list);
if (mporoot<>mpdevfs) then
begin
TAILQ_REMOVE(@mountlist,mpnroot,@mpnroot^.mnt_list);
TAILQ_INSERT_HEAD(@mountlist,mpnroot,@mpnroot^.mnt_list);
end;
TAILQ_INSERT_TAIL(@mountlist,mpdevfs,@mpdevfs^.mnt_list);
mtx_unlock(mountlist_mtx);
//cache_purgevfs(mporoot);
//if (mporoot<>mpdevfs) then
// cache_purgevfs(mpdevfs);
VFS_ROOT(mporoot, LK_EXCLUSIVE, @vporoot);
VI_LOCK(vporoot);
vporoot^.v_iflag:=vporoot^.v_iflag and (not VI_MOUNT);
VI_UNLOCK(vporoot);
vporoot^.v_mountedhere:=nil;
mporoot^.mnt_flag:=mporoot^.mnt_flag and (not MNT_ROOTFS);
mporoot^.mnt_vnodecovered:=nil;
vput(vporoot);
{ Set up the new rootvnode, and purge the cache }
mpnroot^.mnt_vnodecovered:=nil;
set_rootvnode();
//cache_purgevfs(rootvnode^.v_mount);
//mount_print;
{ Remount devfs under /dev }
NDINIT(@nd, LOOKUP, FOLLOW or LOCKLEAF, UIO_SYSSPACE, '/dev', curkthread);
error:=nd_namei(@nd);
if (error=0) then
begin
vp:=nd.ni_vp;
if (vp^.v_type=VDIR) then
error:=0
else
error:=ENOTDIR;
//if (error=0) then
// error:=vinvalbuf(vp, V_SAVE, 0, 0);
if (error=0) then
begin
vpdevfs:=mpdevfs^.mnt_vnodecovered;
if (vpdevfs<>nil) then
begin
//cache_purge(vpdevfs);
vpdevfs^.v_mountedhere:=nil;
vrele(vpdevfs);
end;
mpdevfs^.mnt_vnodecovered:=vp;
vp^.v_mountedhere:=mpdevfs;
VOP_UNLOCK(vp, 0);
end else
vput(vp);
end;
if (error<>0) then
Writeln('mountroot: unable to remount devfs under /dev ', error);
NDFREE(@nd, NDF_ONLY_PNBUF);
if (mporoot=mpdevfs) then
begin
vfs_unbusy(mpdevfs);
{ Unlink the no longer needed /dev/dev ^. / symlink }
//error:=kern_unlink('/dev/dev', UIO_SYSSPACE);
//if (error<>0) then
// Writeln('mountroot: unable to unlink /dev/dev ', error);
end;
Exit(0);
end;
function vfs_mount_path(fstype,fspath,from,opts:PChar;flags:QWORD):Integer;
const
ERRMSGL=255;
var
ma:p_mntarg;
errmsg:RawByteString;
begin
errmsg:='';
SetLength(errmsg,ERRMSGL);
FillChar(PChar(errmsg)^,ERRMSGL,0);
if (vfs_byname(fstype)=nil) then
begin
strlcopy(PChar(errmsg),'unknown file system',ERRMSGL);
Exit(ENOENT);
end;
ma:=nil;
ma:=mount_arg(ma, 'fstype', fstype, -1);
ma:=mount_arg(ma, 'fspath', fspath, -1);
ma:=mount_arg(ma, 'from' , from , -1);
ma:=mount_arg(ma, 'errmsg', PChar(errmsg), ERRMSGL);
ma:=parse_mountroot_options(ma, opts);
Result:=kernel_nmount(ma,flags);
end;
function mount_mkdir(path:PChar):Integer;
begin
Result:=kern_mkdir(path,UIO_SYSSPACE,&777);
end;
function mount_rmdir(path:PChar):Integer;
begin
Result:=kern_rmdir(path,UIO_SYSSPACE);
end;
function mount_into_sandbox(fstype,fspath,from,opts:PChar;flags:QWORD):Integer;
begin
Result:=kern_mkdir(fspath,UIO_SYSSPACE,&777);
if (Result=0) or (Result=EEXIST) then
begin
Result:=vfs_mount_path(fstype,fspath,from,opts,flags);
end;
end;
function unmount_from_sandbox(path:PChar;flags:Integer):Integer;
begin
Result:=kern_unmount(path,flags);
if (Result=0) then
begin
Result:=kern_rmdir(path,UIO_SYSSPACE);
end;
end;
procedure vfs_mountroot();
label
_end;
var
mp:p_mount;
error:Integer;
begin
mtx_lock(VFS_Giant);
error:=vfs_mountroot_devfs(@mp);
if (error<>0) then goto _end;
//mount_print;
error:=vfs_mount_path('ufs','/','/',nil,MNT_ROOTFS);
if (error<>0) then goto _end;
//mount_print;
error:=vfs_mountroot_shuffle(mp);
{
error:=kern_mkdir('null',UIO_SYSSPACE,&777);
if (error=0) then
begin
error:=vfs_mountroot_simple('nullfs','/null','/dev',nil,0);
end;
}
//error:=vfs_mount_mkdir('ufs','/app0','/',nil,0);
//error:=vfs_mount_mkdir('ufs','/system','/system',nil,0);
//
//mount_print;
_end:
mtx_unlock(VFS_Giant);
end;
end.