FPPS4/sys/fs/devfs/devfs_vfsops.pas

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.