mirror of https://github.com/red-prig/fpPS4.git
300 lines
5.7 KiB
Plaintext
300 lines
5.7 KiB
Plaintext
unit devfs_vfsops;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
kern_param,
|
|
vnode,
|
|
vmount,
|
|
devfs_int,
|
|
devfs,
|
|
kern_id;
|
|
|
|
var
|
|
devfs_unr:p_id_desc_table;
|
|
|
|
function devfs_mount(mp:p_mount):Integer;
|
|
function devfs_unmount(mp:p_mount;mntflags:Integer):Integer;
|
|
function devfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
|
|
function devfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
|
procedure devfs_unmount_final(fmp:p_devfs_mount);
|
|
|
|
const
|
|
devfs_opts:array[0..3] of PChar=(
|
|
'from','export','ruleset',nil
|
|
);
|
|
|
|
_devfs_vfsops:vfsops=(
|
|
vfs_mount :@devfs_mount;
|
|
vfs_cmount :nil;
|
|
vfs_unmount :@devfs_unmount;
|
|
vfs_root :@devfs_root;
|
|
vfs_quotactl :nil;
|
|
vfs_statfs :@devfs_statfs;
|
|
vfs_sync :nil;
|
|
vfs_vget :nil;
|
|
vfs_fhtovp :nil;
|
|
vfs_checkexp :nil;
|
|
vfs_init :nil;
|
|
vfs_uninit :nil;
|
|
vfs_extattrctl :nil;
|
|
vfs_sysctl :nil;
|
|
vfs_susp_clean :nil;
|
|
);
|
|
|
|
var
|
|
//VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC or VFCF_JAIL);
|
|
devfs_vfsconf:vfsconf=(
|
|
vfc_version :VFS_VERSION;
|
|
vfc_name :'devfs';
|
|
vfc_vfsops :@_devfs_vfsops;
|
|
vfc_typenum :-1;
|
|
vfc_refcount:0;
|
|
vfc_flags :VFCF_SYNTHETIC or VFCF_JAIL;
|
|
vfc_opts :nil;
|
|
vfc_list :(tqe_next:nil;tqe_prev:nil)
|
|
);
|
|
|
|
implementation
|
|
|
|
uses
|
|
errno,
|
|
kern_mtx,
|
|
kern_sx,
|
|
vfs_mount,
|
|
vfs_subr,
|
|
vnode_if,
|
|
devfs_devs;
|
|
|
|
var
|
|
unr_desc:t_id_desc=(free:nil;refs:0); //temp
|
|
|
|
function VFSTODEVFS(mp:p_mount):p_devfs_mount; inline;
|
|
begin
|
|
Result:=mp^.mnt_data;
|
|
end;
|
|
|
|
function new_unrhdr(min,max:Integer):p_id_desc_table;
|
|
begin
|
|
Result:=AllocMem(SizeOf(t_id_desc_table));
|
|
id_table_init(Result,min,max);
|
|
end;
|
|
|
|
function alloc_unr(p:p_id_desc_table):Integer;
|
|
begin
|
|
if id_new(p,@unr_desc,@Result) then
|
|
begin
|
|
id_release(@unr_desc); //<-id_new
|
|
end else
|
|
begin
|
|
Result:=-1;
|
|
end;
|
|
end;
|
|
|
|
procedure free_unr(p:p_id_desc_table;i:Integer);
|
|
begin
|
|
id_del(p,i,nil);
|
|
end;
|
|
|
|
{
|
|
* Mount the filesystem
|
|
}
|
|
function devfs_mount(mp:p_mount):Integer;
|
|
var
|
|
error:Integer;
|
|
fmp:p_devfs_mount;
|
|
rvp:p_vnode;
|
|
{injail,}rsnum:Integer;
|
|
begin
|
|
|
|
if (devfs_unr=nil) then
|
|
devfs_unr:=new_unrhdr(0, High(Integer));
|
|
|
|
error:=0;
|
|
|
|
if ((mp^.mnt_flag and MNT_ROOTFS)<>0) then
|
|
Exit(EOPNOTSUPP);
|
|
|
|
//if (!prison_allow(td^.td_ucred, PR_ALLOW_MOUNT_DEVFS))
|
|
// Exit(EPERM);
|
|
|
|
rsnum:=0;
|
|
//injail:=jailed(td^.td_ucred);
|
|
|
|
if (mp^.mnt_optnew<>nil) then
|
|
begin
|
|
if (vfs_filteropt(mp^.mnt_optnew, devfs_opts)<>0) then
|
|
Exit(EINVAL);
|
|
|
|
if (vfs_flagopt(mp^.mnt_optnew, 'export', nil, 0)<>0) then
|
|
Exit(EOPNOTSUPP);
|
|
|
|
if (vfs_getopt(mp^.mnt_optnew, 'ruleset', nil, nil)=0) and
|
|
((vfs_scanopt(mp^.mnt_optnew, 'ruleset', '%d',[rsnum])<>1) or
|
|
(rsnum < 0) or
|
|
(rsnum > 65535)) then
|
|
begin
|
|
vfs_mount_error(mp, '%s', ['invalid ruleset specification']);
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
//if (injail) and
|
|
// (rsnum<>0) and
|
|
// (rsnum<>td^.td_ucred^.cr_prison^.pr_devfs_rsnum) then
|
|
// Exit(EPERM);
|
|
end;
|
|
|
|
{ jails enforce their ruleset }
|
|
//if (injail<>0) then
|
|
// rsnum:=td^.td_ucred^.cr_prison^.pr_devfs_rsnum;
|
|
|
|
if ((mp^.mnt_flag and MNT_UPDATE)<>0) then
|
|
begin
|
|
if (rsnum<>0) then
|
|
begin
|
|
fmp:=mp^.mnt_data;
|
|
if (fmp<>nil) then
|
|
begin
|
|
sx_xlock(@fmp^.dm_lock);
|
|
devfs_ruleset_set(devfs_rsnum(rsnum), fmp);
|
|
devfs_ruleset_apply(fmp);
|
|
sx_xunlock(@fmp^.dm_lock);
|
|
end;
|
|
end;
|
|
Exit(0);
|
|
end;
|
|
|
|
fmp:=AllocMem(sizeof(t_devfs_mount));
|
|
fmp^.dm_idx:=alloc_unr(devfs_unr);
|
|
sx_init(@fmp^.dm_lock, 'devfsmount');
|
|
fmp^.dm_holdcnt:=1;
|
|
|
|
MNT_ILOCK(mp);
|
|
mp^.mnt_flag:=mp^.mnt_flag or MNT_LOCAL;
|
|
mp^.mnt_kern_flag:=mp^.mnt_kern_flag or MNTK_MPSAFE or MNTK_LOOKUP_SHARED or MNTK_EXTENDED_SHARED;
|
|
|
|
//MAC
|
|
//mp^.mnt_flag:=mp^.mnt_flag or MNT_MULTILABEL;
|
|
|
|
MNT_IUNLOCK(mp);
|
|
fmp^.dm_mount:=mp;
|
|
mp^.mnt_data:=fmp;
|
|
vfs_getnewfsid(mp);
|
|
|
|
fmp^.dm_rootdir:=devfs_vmkdir(fmp, nil, 0, nil, DEVFS_ROOTINO);
|
|
|
|
error:=devfs_root(mp, LK_EXCLUSIVE, @rvp);
|
|
if (error<>0) then
|
|
begin
|
|
sx_xlock(@fmp^.dm_lock);
|
|
devfs_purge(fmp,fmp^.dm_rootdir);
|
|
sx_xunlock(@fmp^.dm_lock);
|
|
sx_destroy(@fmp^.dm_lock);
|
|
free_unr(devfs_unr, fmp^.dm_idx);
|
|
FreeMem(fmp);
|
|
Exit(error);
|
|
end;
|
|
|
|
if (rsnum<>0) then
|
|
begin
|
|
sx_xlock(@fmp^.dm_lock);
|
|
devfs_ruleset_set(devfs_rsnum(rsnum), fmp);
|
|
sx_xunlock(@fmp^.dm_lock);
|
|
end;
|
|
|
|
VOP_UNLOCK(rvp, 0);
|
|
|
|
vfs_mountedfrom(mp, 'devfs');
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
procedure devfs_unmount_final(fmp:p_devfs_mount); public;
|
|
begin
|
|
sx_destroy(@fmp^.dm_lock);
|
|
FreeMem(fmp);
|
|
end;
|
|
|
|
function devfs_unmount(mp:p_mount;mntflags:Integer):Integer;
|
|
var
|
|
error:Integer;
|
|
flags:Integer;
|
|
fmp:p_devfs_mount;
|
|
hold:Integer;
|
|
idx:DWORD;
|
|
begin
|
|
flags:=0;
|
|
|
|
fmp:=VFSTODEVFS(mp);
|
|
Assert(fmp^.dm_mount<>nil,'devfs_unmount unmounted devfs_mount');
|
|
|
|
{ There is 1 extra root vnode reference from devfs_mount(). }
|
|
error:=vflush(mp, 1, flags);
|
|
if (error<>0) then
|
|
Exit(error);
|
|
|
|
sx_xlock(@fmp^.dm_lock);
|
|
|
|
devfs_cleanup(fmp);
|
|
devfs_rules_cleanup(fmp);
|
|
|
|
fmp^.dm_mount:=nil;
|
|
|
|
Dec(fmp^.dm_holdcnt);
|
|
hold:=fmp^.dm_holdcnt;
|
|
|
|
mp^.mnt_data:=nil;
|
|
idx:=fmp^.dm_idx;
|
|
|
|
sx_xunlock(@fmp^.dm_lock);
|
|
|
|
free_unr(devfs_unr, idx);
|
|
|
|
if (hold=0) then
|
|
devfs_unmount_final(fmp);
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
{ Exitlocked reference to root. }
|
|
|
|
function devfs_root(mp:p_mount;flags:Integer;vpp:pp_vnode):Integer;
|
|
var
|
|
error:Integer;
|
|
vp:p_vnode;
|
|
dmp:p_devfs_mount;
|
|
begin
|
|
dmp:=VFSTODEVFS(mp);
|
|
|
|
sx_xlock(@dmp^.dm_lock);
|
|
error:=devfs_allocv(dmp^.dm_rootdir, mp, LK_EXCLUSIVE, @vp);
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
vp^.v_vflag:=vp^.v_vflag or VV_ROOT;
|
|
vpp^:=vp;
|
|
Exit(0);
|
|
end;
|
|
|
|
function devfs_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
|
begin
|
|
sbp^.f_flags :=0;
|
|
sbp^.f_bsize :=DEV_BSIZE;
|
|
sbp^.f_iosize:=DEV_BSIZE;
|
|
sbp^.f_blocks:=2; { 1K to keep df happy }
|
|
sbp^.f_bfree :=0;
|
|
sbp^.f_bavail:=0;
|
|
sbp^.f_files :=0;
|
|
sbp^.f_ffree :=0;
|
|
Exit(0);
|
|
end;
|
|
|
|
|
|
end.
|
|
|